This is an automated email from the ASF dual-hosted git repository.

gitgabrio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git


The following commit(s) were added to refs/heads/main by this push:
     new 3d6058675d [incubator-kie-issues#854] DMN - Add implicit type 
conversion of date to date and time when necessary (#5664)
3d6058675d is described below

commit 3d6058675d3bd2c6d1b8f07257fa9b614a7fb91f
Author: Gabriele Cardosi <[email protected]>
AuthorDate: Wed Feb 7 15:23:16 2024 +0100

    [incubator-kie-issues#854] DMN - Add implicit type conversion of date to 
date and time when necessary (#5664)
    
    * [private-bamoe-issues#244] DMN - Add implicit type conversion of date to 
date and time when necessary
    
    * [private-bamoe-issues#244] WIP
    
    * [private-bamoe-issues#244] WIP
    
    * [incubator-kie-issues#854] Experiment implicit date -> date-time 
conversion
    
    * [incubator-kie-issues#854] Remove implicit date -> date-time conversion
    
    * [incubator-kie-issues#854] Remove implicit date -> date-time conversion
    
    * [incubator-kie-issues#854] Converting value after its evaluation, when 
needed
    
    * [incubator-kie-issues#854] Minor modification on test
    
    * [incubator-kie-issues#854] WIP
    
    * [incubator-kie-issues#854] Centralize Coerce behaviour
    
    * [incubator-kie-issues#854] Add tests. Removed strong assumption where 
Date is always to be treated as DateTime (not true).
    Removed redundant code on DMNType
    
    * [incubator-kie-issues#854] Enforcing coercion inside lists
    
    * [incubator-kie-issues#854] Enforcing coercion inside collections
    
    ---------
    
    Co-authored-by: BAMOE CI <[email protected]>
    Co-authored-by: Gabriele-Cardosi <[email protected]>
---
 .../org/kie/dmn/core/ast/DMNContextEvaluator.java  |  12 +-
 .../core/ast/DMNFunctionDefinitionEvaluator.java   |   7 +-
 .../org/kie/dmn/core/impl/CompositeTypeImpl.java   |   2 +-
 .../java/org/kie/dmn/core/impl/DMNRuntimeImpl.java |  12 +-
 .../java/org/kie/dmn/core/util/CoerceUtil.java     |  58 +++++++
 .../test/java/org/kie/dmn/core/DMNRuntimeTest.java |  20 +++
 .../kie/dmn/core/DMNStronglyTypedSupportTest.java  |   1 +
 .../kie/dmn/core/ast/DMNContextEvaluatorTest.java  |  76 +++++++++
 .../java/org/kie/dmn/core/util/CoerceUtilTest.java | 176 +++++++++++++++++++++
 .../java/org/kie/dmn/core/util/DMNRuntimeUtil.java |  18 ++-
 .../resources/org/kie/dmn/core/0007-date-time.dmn  |   6 +
 .../org/kie/dmn/core/DateToDateTimeFunction.dmn    |  24 +++
 .../feel/runtime/functions/BaseFEELFunction.java   |  31 ++--
 .../dmn/feel/runtime/functions/DateFunction.java   |   6 +-
 .../java/org/kie/dmn/feel/util/CoerceUtil.java     |  90 +++++++++++
 .../java/org/kie/dmn/feel/util/EvalHelper.java     |   6 +
 .../kie/dmn/feel/runtime/FEELFunctionsTest.java    |  20 +--
 .../java/org/kie/dmn/feel/util/CoerceUtilTest.java | 148 +++++++++++++++++
 18 files changed, 655 insertions(+), 58 deletions(-)

diff --git 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNContextEvaluator.java
 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNContextEvaluator.java
index 9e710d761f..4fbb5c0c64 100644
--- 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNContextEvaluator.java
+++ 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNContextEvaluator.java
@@ -19,7 +19,6 @@
 package org.kie.dmn.core.ast;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -45,6 +44,8 @@ import org.kie.dmn.model.api.FunctionDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.kie.dmn.core.util.CoerceUtil.coerceValue;
+
 public class DMNContextEvaluator
         implements DMNExpressionEvaluator {
     private static final Logger logger       = LoggerFactory.getLogger( 
DMNContextEvaluator.class );
@@ -98,14 +99,7 @@ public class DMNContextEvaluator
                     }
                     EvaluatorResult er = ed.getEvaluator().evaluate( 
eventManager, result );
                     if ( er.getResultType() == ResultType.SUCCESS ) {
-                        Object value = er.getResult();
-                        if( ! ed.getType().isCollection() && value instanceof 
Collection &&
-                            ((Collection)value).size()==1 ) {
-                            // spec defines that "a=[a]", i.e., singleton 
collections should be treated as the single element
-                            // and vice-versa
-                            value = ((Collection)value).toArray()[0];
-                        }
-                        
+                        Object value = coerceValue(ed.getType(), 
er.getResult());
                         if (((DMNRuntimeImpl) 
eventManager.getRuntime()).performRuntimeTypeCheck(result.getModel())) {
                             if (!(ed.getContextEntry().getExpression() 
instanceof FunctionDefinition)) {
                                 // checking directly the result type...
diff --git 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNFunctionDefinitionEvaluator.java
 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNFunctionDefinitionEvaluator.java
index ebb45e7e28..c7d6469aac 100644
--- 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNFunctionDefinitionEvaluator.java
+++ 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNFunctionDefinitionEvaluator.java
@@ -48,6 +48,8 @@ import org.kie.dmn.model.api.FunctionDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.kie.dmn.core.util.CoerceUtil.coerceValue;
+
 public class DMNFunctionDefinitionEvaluator
         implements DMNExpressionEvaluator {
     private static final Logger logger = LoggerFactory.getLogger( 
DMNFunctionDefinitionEvaluator.class );
@@ -157,8 +159,9 @@ public class DMNFunctionDefinitionEvaluator
                     closureContext.getAll().forEach(dmnContext::set);
                     for( int i = 0; i < params.length; i++ ) {
                         final String paramName = parameters.get(i).name;
-                        if ((!performRuntimeTypeCheck) || 
parameters.get(i).type.isAssignableValue(params[i])) {
-                            ctx.setValue(paramName, params[i]);
+                        Object coercedObject = 
coerceValue(parameters.get(i).type, params[i]);
+                        if ((!performRuntimeTypeCheck) || 
parameters.get(i).type.isAssignableValue(coercedObject)) {
+                            ctx.setValue(paramName, coercedObject);
                         } else {
                             ctx.setValue(paramName, null);
                             MsgUtil.reportMessage(logger,
diff --git 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/CompositeTypeImpl.java
 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/CompositeTypeImpl.java
index 491e7676dc..3b15131b80 100644
--- 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/CompositeTypeImpl.java
+++ 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/CompositeTypeImpl.java
@@ -92,7 +92,7 @@ public class CompositeTypeImpl
     public CompositeTypeImpl clone() {
         return new CompositeTypeImpl( getNamespace(), getName(), getId(), 
isCollection(), new LinkedHashMap<>( fields), getBaseType(), getFeelType() );
     }
-    
+
     @Override
     protected boolean internalIsInstanceOf(Object o) {
         if (getBaseType() != null) {
diff --git 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
index a0dc822fc7..a8f205084f 100644
--- 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
+++ 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
@@ -65,6 +65,7 @@ import org.slf4j.LoggerFactory;
 import static 
org.kie.dmn.api.core.DMNDecisionResult.DecisionEvaluationStatus.EVALUATING;
 import static 
org.kie.dmn.api.core.DMNDecisionResult.DecisionEvaluationStatus.FAILED;
 import static 
org.kie.dmn.api.core.DMNDecisionResult.DecisionEvaluationStatus.SKIPPED;
+import static org.kie.dmn.core.util.CoerceUtil.coerceValue;
 
 public class DMNRuntimeImpl
         implements DMNRuntime {
@@ -661,16 +662,9 @@ public class DMNRuntimeImpl
                 return false;
             }
             try {
-                EvaluatorResult er = decision.getEvaluator().evaluate( this, 
result );
+                EvaluatorResult er = decision.getEvaluator().evaluate( this, 
result);
                 if( er.getResultType() == EvaluatorResult.ResultType.SUCCESS ) 
{
-                    Object value = er.getResult();
-                    if( ! decision.getResultType().isCollection() && value 
instanceof Collection &&
-                        ((Collection)value).size()==1 ) {
-                        // spec defines that "a=[a]", i.e., singleton 
collections should be treated as the single element
-                        // and vice-versa
-                        value = ((Collection)value).toArray()[0];
-                    }
-
+                    Object value = coerceValue(decision.getResultType(), 
er.getResult());
                     try {
                         if (typeCheck && 
!d.getResultType().isAssignableValue(value)) {
                             DMNMessage message = MsgUtil.reportMessage( logger,
diff --git 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/util/CoerceUtil.java 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/util/CoerceUtil.java
new file mode 100644
index 0000000000..0d59e4563f
--- /dev/null
+++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/util/CoerceUtil.java
@@ -0,0 +1,58 @@
+/**
+ * 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.kie.dmn.core.util;
+
+import java.time.LocalDate;
+import java.util.Collection;
+
+import org.kie.dmn.api.core.DMNType;
+import org.kie.dmn.core.impl.SimpleTypeImpl;
+import org.kie.dmn.feel.lang.types.BuiltInType;
+import org.kie.dmn.feel.util.EvalHelper;
+
+/**
+ *  Class used to centralize all coercion-related behavior
+ */
+public class CoerceUtil {
+
+    private CoerceUtil() {
+        // singleton class
+    }
+
+    public static Object coerceValue(DMNType requiredType, Object 
valueToCoerce) {
+        return (requiredType != null && valueToCoerce != null) ? 
actualCoerceValue(requiredType, valueToCoerce) :
+                valueToCoerce;
+    }
+
+    static Object actualCoerceValue(DMNType requiredType, Object 
valueToCoerce) {
+        Object toReturn = valueToCoerce;
+        if (!requiredType.isCollection() && valueToCoerce instanceof 
Collection &&
+                ((Collection) valueToCoerce).size() == 1) {
+            // spec defines that "a=[a]", i.e., singleton collections should 
be treated as the single element
+            // and vice-versa
+            return ((Collection) valueToCoerce).toArray()[0];
+        }
+        if (valueToCoerce instanceof LocalDate localDate &&
+                requiredType instanceof SimpleTypeImpl simpleType &&
+                simpleType.getFeelType() == BuiltInType.DATE_TIME) {
+            return EvalHelper.coerceDateTime(localDate);
+        }
+        return toReturn;
+    }
+}
\ No newline at end of file
diff --git 
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java
index d8ea262221..a5198f90a2 100644
--- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java
+++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java
@@ -25,6 +25,7 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.OffsetTime;
 import java.time.Period;
+import java.time.ZoneId;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.time.chrono.ChronoPeriod;
@@ -634,6 +635,7 @@ public class DMNRuntimeTest extends 
BaseInterpretedVsCompiledTest {
         assertThat(ctx.get("Date-Time")).isEqualTo( ZonedDateTime.of( 2016, 
12, 24, 23, 59, 0, 0, ZoneOffset.ofHours( -5 )));
         assertThat(ctx.get("Date")).isEqualTo( new HashMap<String, Object>(  ) 
{{
             put( "fromString", LocalDate.of( 2015, 12, 24 ) );
+            put( "fromStringToDateTime", ZonedDateTime.of( 2015, 12, 24, 0, 0, 
0, 0, ZoneOffset.UTC) );
             put( "fromDateTime", LocalDate.of( 2016, 12, 24 ) );
             put( "fromYearMonthDay", LocalDate.of( 1999, 11, 22 ) );
         }});
@@ -658,6 +660,24 @@ public class DMNRuntimeTest extends 
BaseInterpretedVsCompiledTest {
 
     }
 
+    @Test
+    public void testDateToDateTimeFunction() {
+        final DMNRuntime runtime = 
DMNRuntimeUtil.createRuntime("DateToDateTimeFunction.dmn", this.getClass());
+        final DMNModel dmnModel = 
runtime.getModel("https://kiegroup.org/dmn/_A7F17D7B-F0AB-4C0B-B521-02EA26C2FBEE";,
+                                                   "new-file");
+        assertThat(dmnModel).isNotNull();
+        
assertThat(dmnModel.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnModel.getMessages())).isFalse();
+
+        final DMNContext ctx = runtime.newContext();
+
+        final DMNResult dmnResult = runtime.evaluateAll(dmnModel, ctx);
+        LOG.debug("{}", dmnResult);
+        
assertThat(dmnResult.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnResult.getMessages())).isFalse();
+
+        ZonedDateTime expected = ZonedDateTime.of(LocalDate.of(2021, 05, 31), 
LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC);
+        
assertThat(dmnResult.getDecisionResultByName("usingNormal").getResult()).isEqualTo(expected);
+    }
+
     @Test
     public void testFiltering() {
         final DMNRuntime runtime = 
DMNRuntimeUtil.createRuntime("Person_filtering_by_age.dmn", getClass() );
diff --git 
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNStronglyTypedSupportTest.java
 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNStronglyTypedSupportTest.java
index 24dc9de7b4..bb9ab591bd 100644
--- 
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNStronglyTypedSupportTest.java
+++ 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNStronglyTypedSupportTest.java
@@ -165,6 +165,7 @@ public class DMNStronglyTypedSupportTest extends 
BaseVariantTest {
             assertThat(ctx.get("Date-Time")).isEqualTo(ZonedDateTime.of(2016, 
12, 24, 23, 59, 0, 0, ZoneOffset.ofHours(-5)));
             assertThat(ctx.get("Date")).isEqualTo(new HashMap<String, 
Object>() {{
                 put("fromString", LocalDate.of(2015, 12, 24));
+                put( "fromStringToDateTime", ZonedDateTime.of( 2015, 12, 24, 
0, 0, 0, 0, ZoneOffset.UTC) );
                 put("fromDateTime", LocalDate.of(2016, 12, 24));
                 put("fromYearMonthDay", LocalDate.of(1999, 11, 22));
             }});
diff --git 
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/ast/DMNContextEvaluatorTest.java
 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/ast/DMNContextEvaluatorTest.java
new file mode 100644
index 0000000000..a7183d95c0
--- /dev/null
+++ 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/ast/DMNContextEvaluatorTest.java
@@ -0,0 +1,76 @@
+package org.kie.dmn.core.ast;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.util.stream.Collectors;
+
+import org.drools.util.FileUtils;
+import org.junit.Test;
+import org.kie.dmn.api.core.DMNContext;
+import org.kie.dmn.api.core.DMNModel;
+import org.kie.dmn.api.core.DMNRuntime;
+import org.kie.dmn.api.core.ast.DecisionNode;
+import org.kie.dmn.core.api.DMNExpressionEvaluator;
+import org.kie.dmn.core.api.DMNFactory;
+import org.kie.dmn.core.api.EvaluatorResult;
+import org.kie.dmn.core.impl.DMNDecisionResultImpl;
+import org.kie.dmn.core.impl.DMNResultImpl;
+import org.kie.dmn.core.impl.DMNResultImplFactory;
+import org.kie.dmn.core.util.DMNRuntimeUtil;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class DMNContextEvaluatorTest {
+
+    private DMNResultImplFactory dmnResultFactory = new DMNResultImplFactory();
+
+    @Test
+    public void  dateToDateTime() {
+        File file = FileUtils.getFile("0007-date-time.dmn");
+        final DMNRuntime runtime = DMNRuntimeUtil.createRuntime(file);
+        final DMNModel dmnModel = 
runtime.getModel("http://www.trisotech.com/definitions/_69430b3e-17b8-430d-b760-c505bf6469f9";,
 "dateTime Table 58");
+        assertThat(dmnModel).isNotNull();
+        
assertThat(dmnModel.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnModel.getMessages())).isFalse();
+
+        DecisionNode date = dmnModel.getDecisionByName("Date");
+        DMNExpressionEvaluator dateDecisionEvaluator = ((DecisionNodeImpl) 
date).getEvaluator();
+        DMNContextEvaluator.ContextEntryDef ed = ((DMNContextEvaluator) 
dateDecisionEvaluator).getEntries().stream()
+                .filter(entry -> 
entry.getName().equals("fromStringToDateTime"))
+                .findFirst()
+                .orElseThrow(() -> new RuntimeException("Failed to find 
fromStringToDateTime ContextEntryDef"));
+        final DMNContext context = DMNFactory.newContext();
+        context.set( "dateString", "2015-12-24" );
+        context.set( "timeString", "00:00:01-01:00" );
+        context.set( "dateTimeString", "2016-12-24T23:59:00-05:00" );
+        context.set( "Hours", 12 );
+        context.set( "Minutes", 59 );
+        context.set( "Seconds", new BigDecimal("1.3" ) );
+        context.set( "Timezone", "PT-1H" );
+        context.set( "Year", 1999 );
+        context.set( "Month", 11 );
+        context.set( "Day", 22 );
+        context.set( "durationString", "P13DT2H14S" );      // <variable 
name="durationString" typeRef="feel:string"/>
+        DMNResultImpl result = createResult(dmnModel, context );
+        DMNExpressionEvaluator evaluator = ed.getEvaluator();
+        EvaluatorResult evaluated = evaluator.evaluate(runtime, result);
+        assertNotNull(evaluated);
+        assertEquals(EvaluatorResult.ResultType.SUCCESS, 
evaluated.getResultType());
+    }
+
+    private DMNResultImpl createResult(DMNModel model, DMNContext context) {
+        DMNResultImpl result = createResultImpl(model, context);
+
+        for (DecisionNode decision : model.getDecisions().stream().filter(d -> 
d.getModelNamespace().equals(model.getNamespace())).collect(Collectors.toSet()))
 {
+            result.addDecisionResult(new 
DMNDecisionResultImpl(decision.getId(), decision.getName()));
+        }
+        return result;
+    }
+
+    private DMNResultImpl createResultImpl(DMNModel model, DMNContext context) 
{
+        DMNResultImpl result = dmnResultFactory.newDMNResultImpl(model);
+        result.setContext(context.clone());
+        return result;
+    }
+}
\ No newline at end of file
diff --git 
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/CoerceUtilTest.java 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/CoerceUtilTest.java
new file mode 100644
index 0000000000..73c60e35dc
--- /dev/null
+++ 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/CoerceUtilTest.java
@@ -0,0 +1,176 @@
+package org.kie.dmn.core.util;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.Collections;
+
+import org.junit.Test;
+import org.kie.dmn.api.core.DMNType;
+import org.kie.dmn.core.impl.SimpleTypeImpl;
+import org.kie.dmn.feel.lang.types.BuiltInType;
+
+import static org.junit.Assert.*;
+
+public class CoerceUtilTest {
+
+    @Test
+    public void coerceValueCollectionToArrayConverted() {
+        Object item = "TESTED_OBJECT";
+        Object value = Collections.singleton(item);
+        DMNType requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                  "string",
+                                                  null,
+                                                  false,
+                                                  null,
+                                                  null,
+                                                  BuiltInType.STRING);
+        Object retrieved = CoerceUtil.coerceValue(requiredType, value);
+        assertNotNull(retrieved);
+        assertEquals(item, retrieved);
+    }
+
+    @Test
+    public void coerceValueCollectionToArrayNotConverted() {
+        Object item = "TESTED_OBJECT";
+        Object value = Collections.singleton(item);
+        DMNType requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                  "string",
+                                                  null,
+                                                  true,
+                                                  null,
+                                                  null,
+                                                  BuiltInType.STRING);
+        Object retrieved = CoerceUtil.coerceValue(requiredType, value);
+        assertNotNull(retrieved);
+        assertEquals(value, retrieved);
+
+        value = "TESTED_OBJECT";
+        requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                  "string",
+                                                  null,
+                                                  false,
+                                                  null,
+                                                  null,
+                                                  BuiltInType.STRING);
+        retrieved = CoerceUtil.coerceValue(requiredType, value);
+        assertNotNull(retrieved);
+        assertEquals(value, retrieved);
+
+        requiredType = null;
+        retrieved = CoerceUtil.coerceValue(requiredType, value);
+        assertEquals(value, retrieved);
+
+        value = null;
+        requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                         "string",
+                                                         null,
+                                                         false,
+                                                         null,
+                                                         null,
+                                                         BuiltInType.STRING);
+        retrieved = CoerceUtil.coerceValue(requiredType, value);
+        assertEquals(value, retrieved);
+
+    }
+
+    @Test
+    public void coerceValueDateToDateTimeConverted() {
+        Object value = LocalDate.now();
+        DMNType requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                  "date and time",
+                                                  null,
+                                                  false,
+                                                  null,
+                                                  null,
+                                                  BuiltInType.DATE_TIME);
+        Object retrieved = CoerceUtil.coerceValue(requiredType, value);
+        assertNotNull(retrieved);
+        assertTrue(retrieved instanceof ZonedDateTime);
+        ZonedDateTime zdtRetrieved = (ZonedDateTime)retrieved;
+        assertEquals(value, zdtRetrieved.toLocalDate());
+        assertEquals(ZoneOffset.UTC, zdtRetrieved.getOffset());
+        assertEquals(0, zdtRetrieved.getHour());
+        assertEquals(0, zdtRetrieved.getMinute());
+        assertEquals(0, zdtRetrieved.getSecond());
+    }
+
+    @Test
+    public void coerceValueDateToDateTimeNotConverted() {
+        Object value = "TEST_OBJECT";
+        DMNType requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                  "date and time",
+                                                  null,
+                                                  false,
+                                                  null,
+                                                  null,
+                                                  BuiltInType.DATE_TIME);
+        Object retrieved = CoerceUtil.coerceValue(requiredType, value);
+        assertNotNull(retrieved);
+        assertEquals(value, retrieved);
+        value = LocalDate.now();
+        requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                  "date",
+                                                  null,
+                                                  false,
+                                                  null,
+                                                  null,
+                                                  BuiltInType.DATE);
+        retrieved = CoerceUtil.coerceValue(requiredType, value);
+        assertNotNull(retrieved);
+        assertEquals(value, retrieved);
+    }
+
+    @Test
+    public void actualCoerceValueCollectionToArray() {
+        Object item = "TESTED_OBJECT";
+        Object value = Collections.singleton(item);
+        DMNType requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                  "string",
+                                                  null,
+                                                  false,
+                                                  null,
+                                                  null,
+                                                  BuiltInType.STRING);
+        Object retrieved = CoerceUtil.actualCoerceValue(requiredType, value);
+        assertNotNull(retrieved);
+        assertEquals(item, retrieved);
+    }
+
+    @Test
+    public void actualCoerceValueDateToDateTime() {
+        Object value = LocalDate.now();
+        DMNType requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                  "date and time",
+                                                  null,
+                                                  false,
+                                                  null,
+                                                  null,
+                                                  BuiltInType.DATE_TIME);
+        Object retrieved = CoerceUtil.actualCoerceValue(requiredType, value);
+        assertNotNull(retrieved);
+        assertTrue(retrieved instanceof ZonedDateTime);
+        ZonedDateTime zdtRetrieved = (ZonedDateTime)retrieved;
+        assertEquals(value, zdtRetrieved.toLocalDate());
+        assertEquals(ZoneOffset.UTC, zdtRetrieved.getOffset());
+        assertEquals(0, zdtRetrieved.getHour());
+        assertEquals(0, zdtRetrieved.getMinute());
+        assertEquals(0, zdtRetrieved.getSecond());
+    }
+
+    @Test
+    public void actualCoerceValueNotConverted() {
+        Object value = BigDecimal.valueOf(1L);
+        DMNType requiredType = new 
SimpleTypeImpl("http://www.omg.org/spec/DMN/20180521/FEEL/";,
+                                                  "number",
+                                                  null,
+                                                  false,
+                                                  null,
+                                                  null,
+                                                  BuiltInType.NUMBER);
+        Object retrieved = CoerceUtil.actualCoerceValue(requiredType, value);
+        assertNotNull(retrieved);
+        assertEquals(value, retrieved);
+    }
+}
\ No newline at end of file
diff --git 
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/DMNRuntimeUtil.java 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/DMNRuntimeUtil.java
index 93624b4e07..102b8ba3de 100644
--- 
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/DMNRuntimeUtil.java
+++ 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/DMNRuntimeUtil.java
@@ -18,6 +18,7 @@
  */
 package org.kie.dmn.core.util;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
@@ -72,10 +73,15 @@ public final class DMNRuntimeUtil {
         final KieContainer kieContainer = KieHelper.getKieContainer(
                 ks.newReleaseId("org.kie", "dmn-test-"+UUID.randomUUID(), 
"1.0"),
                 ks.getResources().newClassPathResource(resourceName, 
testClass));
+        return createRuntime(kieContainer);
+    }
 
-        final DMNRuntime runtime = typeSafeGetKieRuntime(kieContainer);
-        assertThat(runtime).isNotNull();
-        return runtime;
+    public static DMNRuntime createRuntime(final File resourceFile) {
+        final KieServices ks = KieServices.Factory.get();
+        final KieContainer kieContainer = KieHelper.getKieContainer(
+                ks.newReleaseId("org.kie", "dmn-test-"+UUID.randomUUID(), 
"1.0"),
+                ks.getResources().newFileSystemResource(resourceFile));
+        return createRuntime(kieContainer);
     }
     
     public static List<DMNMessage> createExpectingDMNMessages(final String 
resourceName, final Class testClass) {
@@ -192,4 +198,10 @@ public final class DMNRuntimeUtil {
         byte[] jar = kieModule.getBytes();
         return jar;
     }
+
+    static DMNRuntime createRuntime(KieContainer kieContainer) {
+        final DMNRuntime runtime = typeSafeGetKieRuntime(kieContainer);
+        assertThat(runtime).isNotNull();
+        return runtime;
+    }
 }
diff --git 
a/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/0007-date-time.dmn 
b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/0007-date-time.dmn
index 103fabd942..8f765d0114 100644
--- 
a/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/0007-date-time.dmn
+++ 
b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/0007-date-time.dmn
@@ -72,6 +72,12 @@
                <semantic:text>date(dateString)</semantic:text>
             </semantic:literalExpression>
          </semantic:contextEntry>
+        <semantic:contextEntry>
+          <semantic:variable name="fromStringToDateTime" typeRef="date and 
time"/>
+          <semantic:literalExpression>
+            <semantic:text>date(dateString)</semantic:text>
+          </semantic:literalExpression>
+        </semantic:contextEntry>
          <semantic:contextEntry>
             <semantic:variable name="fromDateTime" typeRef="date"/>
             <semantic:literalExpression>
diff --git 
a/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/DateToDateTimeFunction.dmn
 
b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/DateToDateTimeFunction.dmn
new file mode 100644
index 0000000000..b947dfd7f7
--- /dev/null
+++ 
b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/DateToDateTimeFunction.dmn
@@ -0,0 +1,24 @@
+<dmn:definitions xmlns:dmn="http://www.omg.org/spec/DMN/20180521/MODEL/"; 
xmlns="https://kiegroup.org/dmn/_A7F17D7B-F0AB-4C0B-B521-02EA26C2FBEE"; 
xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/"; 
xmlns:kie="http://www.drools.org/kie/dmn/1.2"; 
xmlns:dmndi="http://www.omg.org/spec/DMN/20180521/DMNDI/"; 
xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/"; 
xmlns:feel="http://www.omg.org/spec/DMN/20180521/FEEL/"; 
id="_14BDA5CA-C87F-448D-AF75-F976A9E0EF83" name="new-file" 
typeLanguage="http://www. [...]
+  <dmn:extensionElements/>
+  <dmn:businessKnowledgeModel id="_80847A66-F03E-4B81-B406-0E3B8D177EC8" 
name="normal">
+    <dmn:extensionElements/>
+    <dmn:variable id="_1D5A641F-31EE-42FF-8DAD-D229A9A998BD" name="normal"/>
+    <dmn:encapsulatedLogic id="_4A6C9D35-03DE-47F8-8ADD-6F15A27077A5" 
kind="FEEL">
+      <dmn:formalParameter id="_3984C4F0-4E60-481A-9702-EAC914F1C63B" name="a" 
typeRef="date and time"/>
+      <dmn:formalParameter id="_C419BFC7-53E0-4B2C-A2B1-BA5A22D2971D" name="b" 
typeRef="duration"/>
+      <dmn:literalExpression id="_88CC7676-B609-4430-8670-5B5735D5C6D5">
+        <dmn:text>a+b</dmn:text>
+      </dmn:literalExpression>
+    </dmn:encapsulatedLogic>
+  </dmn:businessKnowledgeModel>
+  <dmn:decision id="_3151179A-E33D-4A7E-9D9C-8CFE388E8640" name="usingNormal">
+    <dmn:extensionElements/>
+    <dmn:variable id="_C1455FFB-C4C4-4ABA-A9DF-2E7A92F2588B" 
name="usingNormal" typeRef="date and time"/>
+    <dmn:knowledgeRequirement id="_A1C84873-809C-44CD-90BE-AD32BFB8F79F">
+      <dmn:requiredKnowledge href="#_80847A66-F03E-4B81-B406-0E3B8D177EC8"/>
+    </dmn:knowledgeRequirement>
+    <dmn:literalExpression id="_B29EE21C-702B-40BB-A98A-1717BBC83C8C">
+      <dmn:text>normal( @"2019-03-31", duration( "P26M" ))</dmn:text>
+    </dmn:literalExpression>
+  </dmn:decision>
+</dmn:definitions>
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java
index 64c76d89bb..ae1fbf5e5f 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java
@@ -24,9 +24,9 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -46,6 +46,8 @@ import org.kie.dmn.feel.util.EvalHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.kie.dmn.feel.util.CoerceUtil.coerceParams;
+
 public abstract class BaseFEELFunction
         implements FEELFunction {
 
@@ -153,10 +155,7 @@ public abstract class BaseFEELFunction
             }
         } catch ( Exception e ) {
             logger.error( "Error trying to call function " + getName() + ".", 
e );
-            ctx.notifyEvt( () -> {
-                                       return new FEELEventBase( 
Severity.ERROR, "Error trying to call function " + getName() + ".", e );
-                                   }
-            );
+            ctx.notifyEvt( () -> new FEELEventBase( Severity.ERROR, "Error 
trying to call function " + getName() + ".", e ));
         }
         return null;
     }
@@ -238,22 +237,12 @@ public abstract class BaseFEELFunction
             boolean found = true;
             for ( int i = 0; i < parameterTypes.length; i++ ) {
                 Class<?> currentIdxActualParameterType = 
cm.getActualClasses()[i];
-                if ( currentIdxActualParameterType != null && 
!parameterTypes[i].isAssignableFrom( currentIdxActualParameterType ) ) {
-                    // singleton list spec defines that "a=[a]", i.e., 
singleton collections should be treated as the single element
-                    // and vice-versa
-                    if ( Collection.class.isAssignableFrom( 
currentIdxActualParameterType ) ) {
-                        Collection<?> valueCollection = (Collection<?>) 
actualParams[i];                    
-                        if ( valueCollection.size() == 1 ) {
-                            Object singletonValue = 
valueCollection.iterator().next();
-                            // re-perform the assignable-from check, this time 
using the element itself the singleton value from the original parameter list
-                            if ( singletonValue != null && 
parameterTypes[i].isAssignableFrom( singletonValue.getClass() ) ) {
-                                Object[] newParams = new 
Object[cm.getActualParams().length];
-                                System.arraycopy( cm.getActualParams(), 0, 
newParams, 0, cm.getActualParams().length ); // can't rely on 
adjustForVariableParameters() have actually copied
-                                newParams[i] = singletonValue;
-                                cm.setActualParams(newParams);
-                                continue;
-                            }
-                        }
+                Class<?> expectedParameterType = parameterTypes[i];
+                if ( currentIdxActualParameterType != null && 
!expectedParameterType.isAssignableFrom( currentIdxActualParameterType ) ) {
+                    Optional<Object[]> coercedParams = 
coerceParams(currentIdxActualParameterType, expectedParameterType, 
actualParams, i);
+                    if (coercedParams.isPresent()) {
+                        cm.setActualParams(coercedParams.get());
+                        continue;
                     }
                     found = false;
                     break;
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java
index 37cd0b3bf2..05f28b8bfd 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java
@@ -62,7 +62,7 @@ public class DateFunction
         if (!BEGIN_YEAR.matcher(val).find()) { // please notice the regex 
strictly requires the beginning, so we can use find.
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "from", "year not compliant with XML 
Schema Part 2 Datatypes"));
         }
-        
+
         try {
             return FEELFnResult.ofResult(LocalDate.from(FEEL_DATE.parse(val)));
         } catch (DateTimeException e) {
@@ -80,7 +80,7 @@ public class DateFunction
         if ( day == null ) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "day", "cannot be null"));
         }
-        
+
         try {
             return FEELFnResult.ofResult( LocalDate.of( year.intValue(), 
month.intValue(), day.intValue() ) );
         } catch (DateTimeException e) {
@@ -92,7 +92,7 @@ public class DateFunction
         if ( date == null ) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "from", "cannot be null"));
         }
-        
+
         try {
             return FEELFnResult.ofResult( LocalDate.from( date ) );
         } catch (DateTimeException e) {
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CoerceUtil.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CoerceUtil.java
new file mode 100644
index 0000000000..4672de1b39
--- /dev/null
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CoerceUtil.java
@@ -0,0 +1,90 @@
+/**
+ * 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.kie.dmn.feel.util;
+
+import java.time.LocalDate;
+import java.time.ZonedDateTime;
+import java.util.Collection;
+import java.util.Optional;
+
+import org.kie.dmn.feel.lang.Type;
+import org.kie.dmn.feel.lang.types.BuiltInType;
+
+/**
+ *  Class used to centralize all coercion-related behavior
+ */
+public class CoerceUtil {
+
+    private CoerceUtil() {
+        // singleton class
+    }
+
+    public static Object coerceParameter(Type requiredType, Object 
valueToCoerce) {
+        return (requiredType != null && valueToCoerce != null) ? 
actualCoerceParameter(requiredType, valueToCoerce) :
+                valueToCoerce;
+    }
+
+    public static Optional<Object[]> coerceParams(Class<?> 
currentIdxActualParameterType, Class<?> expectedParameterType, Object[] 
actualParams, int i) {
+        Object actualObject = actualParams[i];
+        Optional<Object> coercedObject = 
coerceParam(currentIdxActualParameterType, expectedParameterType,
+                                                     actualObject);
+        return coercedObject.map(o -> actualCoerceParams(actualParams, o, i));
+    }
+
+    static Optional<Object> coerceParam(Class<?> 
currentIdxActualParameterType, Class<?> expectedParameterType,
+                                        Object actualObject) {
+        if (Collection.class.isAssignableFrom(currentIdxActualParameterType)) {
+            Collection<?> valueCollection = (Collection<?>) actualObject;
+            if (valueCollection.size() == 1) {
+                Object singletonValue = valueCollection.iterator().next();
+                // re-perform the assignable-from check, this time using the 
element itself the singleton value from
+                // the original parameter list
+                if (singletonValue != null) {
+                    return 
expectedParameterType.isAssignableFrom(singletonValue.getClass()) ?
+                            Optional.of(singletonValue) :
+                            coerceParam(singletonValue.getClass(), 
expectedParameterType, singletonValue);
+                }
+            }
+        }
+        if (actualObject instanceof LocalDate localDate &&
+                ZonedDateTime.class.isAssignableFrom(expectedParameterType)) {
+            Object coercedObject = EvalHelper.coerceDateTime(localDate);
+            return Optional.of(coercedObject);
+        }
+        return Optional.empty();
+    }
+
+    static Object actualCoerceParameter(Type requiredType, Object 
valueToCoerce) {
+        Object toReturn = valueToCoerce;
+        if (valueToCoerce instanceof LocalDate localDate &&
+                requiredType == BuiltInType.DATE_TIME) {
+            return EvalHelper.coerceDateTime(localDate);
+        }
+        return toReturn;
+    }
+
+    static Object[] actualCoerceParams(Object[] actualParams, Object 
coercedObject, int i) {
+        Object[] toReturn = new Object[actualParams.length];
+        System.arraycopy( actualParams, 0, toReturn, 0, actualParams.length );
+        toReturn[i] = coercedObject;
+        return toReturn;
+    }
+
+
+}
\ No newline at end of file
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java
index 3e4a3e00da..4fa56ed075 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java
@@ -24,7 +24,9 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.MathContext;
 import java.time.Duration;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.time.OffsetDateTime;
 import java.time.ZoneId;
 import java.time.ZoneOffset;
@@ -191,6 +193,10 @@ public class EvalHelper {
         }
     }
 
+    public static ZonedDateTime coerceDateTime(final LocalDate value) {
+        return ZonedDateTime.of(value, LocalTime.of(0, 0, 0, 0), 
ZoneOffset.UTC);
+    }
+
     public static Boolean getBooleanOrNull(Object value) {
         if (!(value instanceof Boolean)) {
             return null;
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java
index 5478e9a575..a84998a33c 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java
@@ -187,7 +187,7 @@ public class FEELFunctionsTest extends BaseFEELTest {
                 { "all( true, true )", true, null},
                 { "all( [true, false] )", false, null},
                 { "all( [true, true] )", true, null},
-                { "all( [false,null,true] )", false, null},   
+                { "all( [false,null,true] )", false, null},
                 { "all( [] )", true, null},
                 { "all( 0 )", null, FEELEvent.Severity.ERROR},
                 { "all( )", null, FEELEvent.Severity.ERROR},
@@ -199,32 +199,32 @@ public class FEELFunctionsTest extends BaseFEELTest {
                 { "any( true, true )", true, null},
                 { "any( [true, false] )", true, null},
                 { "any( [true, true] )", true, null},
-                { "any( [false,null,true] )", true, null},   
+                { "any( [false,null,true] )", true, null},
                 { "any( [] )", false, null},
                 { "any( 0 )", null, FEELEvent.Severity.ERROR},
                 { "any( )", null, FEELEvent.Severity.ERROR},
-                
+
                 { "day of year( date(2019, 9, 17) )", BigDecimal.valueOf( 260 
), null},
                 { "day of week( date(2019, 9, 17) )", "Tuesday", null},
                 { "month of year( date(2019, 9, 17) )", "September", null},
                 { "week of year( date(2019, 9, 17) )", BigDecimal.valueOf( 38 
), null},
                 { "week of year( date(2003, 12, 29) )", BigDecimal.valueOf( 1 
), null}, // ISO defs.
-                { "week of year( date(2004, 1, 4) )", BigDecimal.valueOf( 1 ), 
null}, 
-                { "week of year( date(2005, 1, 3) )", BigDecimal.valueOf( 1 ), 
null}, 
-                { "week of year( date(2005, 1, 9) )", BigDecimal.valueOf( 1 ), 
null}, 
-                { "week of year( date(2005, 1, 1) )", BigDecimal.valueOf( 53 
), null}, 
+                { "week of year( date(2004, 1, 4) )", BigDecimal.valueOf( 1 ), 
null},
+                { "week of year( date(2005, 1, 3) )", BigDecimal.valueOf( 1 ), 
null},
+                { "week of year( date(2005, 1, 9) )", BigDecimal.valueOf( 1 ), 
null},
+                { "week of year( date(2005, 1, 1) )", BigDecimal.valueOf( 53 
), null},
                 { "median( 8, 2, 5, 3, 4 )", new BigDecimal("4") , null},
                 { "median( [6, 1, 2, 3] )", new BigDecimal("2.5") , null},
                 { "median( [ ] ) ", null, null}, // DMN spec, Table 69: 
Semantics of list functions
-                
+
                 { "0-max( 1, 2, 3 )", BigDecimal.valueOf( -3 ) , null},
                 { "-max( 1, 2, 3 )", BigDecimal.valueOf( -3 ) , null}, // 
DROOLS-5981
                 { "0-sum( 1, 2, 3 )", BigDecimal.valueOf( -6 ) , null},
                 { "-sum( 1, 2, 3 )", BigDecimal.valueOf( -6 ) , null},
                 { "0-abs( 10 )", new BigDecimal("-10") , null},
-                { "-abs( 10 )", new BigDecimal("-10") , null}, 
+                { "-abs( 10 )", new BigDecimal("-10") , null},
                 { "0-max( 1, abs(-2), 3 )", BigDecimal.valueOf( -3 ) , null},
-                { "-max( 1, abs(-2), 3 )", BigDecimal.valueOf( -3 ) , null}, 
+                { "-max( 1, abs(-2), 3 )", BigDecimal.valueOf( -3 ) , null},
                 { "0-max( 1, -abs(-2), 3 )", BigDecimal.valueOf( -3 ) , null},
                 { "-max( 1, -abs(-2), 3 )", BigDecimal.valueOf( -3 ) , null},
                 { "{a: 2, r: 0-sum( 1, a, 3 )}.r", BigDecimal.valueOf( -6 ) , 
null},
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/CoerceUtilTest.java 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/CoerceUtilTest.java
new file mode 100644
index 0000000000..28413e6d1a
--- /dev/null
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/CoerceUtilTest.java
@@ -0,0 +1,148 @@
+package org.kie.dmn.feel.util;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.Set;
+
+import org.junit.Test;
+import org.kie.dmn.feel.lang.types.BuiltInType;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class CoerceUtilTest {
+
+    @Test
+    public void coerceParameterDateToDateTimeConverted() {
+        Object value = LocalDate.now();
+        Object retrieved = CoerceUtil.coerceParameter(BuiltInType.DATE_TIME, 
value);
+        assertNotNull(retrieved);
+        assertTrue(retrieved instanceof ZonedDateTime);
+        ZonedDateTime zdtRetrieved = (ZonedDateTime) retrieved;
+        assertEquals(value, zdtRetrieved.toLocalDate());
+        assertEquals(ZoneOffset.UTC, zdtRetrieved.getOffset());
+        assertEquals(0, zdtRetrieved.getHour());
+        assertEquals(0, zdtRetrieved.getMinute());
+        assertEquals(0, zdtRetrieved.getSecond());
+    }
+
+    @Test
+    public void coerceParameterDateToDateTimeNotConverted() {
+        Object value = "TEST_OBJECT";
+        Object retrieved = CoerceUtil.coerceParameter(null, value);
+        assertEquals(value, retrieved);
+
+        value = null;
+        retrieved = CoerceUtil.coerceParameter(BuiltInType.DATE, value);
+        assertEquals(value, retrieved);
+    }
+
+    @Test
+    public void coerceParamsCollectionToArrayConverted() {
+        Object item = "TESTED_OBJECT";
+        Object value = Collections.singleton(item);
+        Object[] actualParams1 = {value, "NOT_DATE"};
+        Optional<Object[]> retrieved = CoerceUtil.coerceParams(Set.class, 
String.class, actualParams1, 0);
+        assertNotNull(retrieved);
+        assertTrue(retrieved.isPresent());
+        Object[] retrievedObjects = retrieved.get();
+        assertEquals(item, retrievedObjects[0]);
+        assertEquals(actualParams1[1], retrievedObjects[1]);
+
+
+        item = LocalDate.now();
+        value = Collections.singleton(item);
+        Object[] actualParams2 = {value, "NOT_DATE"};
+        retrieved = CoerceUtil.coerceParams(Set.class, ZonedDateTime.class, 
actualParams2, 0);
+        assertNotNull(retrieved);
+        assertTrue(retrieved.isPresent());
+        retrievedObjects = retrieved.get();
+        assertTrue(retrievedObjects[0] instanceof ZonedDateTime);
+        ZonedDateTime zdtRetrieved = (ZonedDateTime) retrievedObjects[0];
+        assertEquals(item, zdtRetrieved.toLocalDate());
+        assertEquals(ZoneOffset.UTC, zdtRetrieved.getOffset());
+        assertEquals(0, zdtRetrieved.getHour());
+        assertEquals(0, zdtRetrieved.getMinute());
+        assertEquals(0, zdtRetrieved.getSecond());
+        assertEquals(actualParams2[1], retrievedObjects[1]);
+    }
+
+    @Test
+    public void coerceParamsToDateTimeConverted() {
+        Object value = LocalDate.now();
+        Object[] actualParams = {value, "NOT_DATE"};
+        Optional<Object[]> retrieved = 
CoerceUtil.coerceParams(LocalDate.class, ZonedDateTime.class, actualParams, 0);
+        assertNotNull(retrieved);
+        assertTrue(retrieved.isPresent());
+        Object[] retrievedObjects = retrieved.get();
+        assertTrue(retrievedObjects[0] instanceof ZonedDateTime);
+        ZonedDateTime zdtRetrieved = (ZonedDateTime) retrievedObjects[0];
+        assertEquals(value, zdtRetrieved.toLocalDate());
+        assertEquals(ZoneOffset.UTC, zdtRetrieved.getOffset());
+        assertEquals(0, zdtRetrieved.getHour());
+        assertEquals(0, zdtRetrieved.getMinute());
+        assertEquals(0, zdtRetrieved.getSecond());
+        assertEquals(actualParams[1], retrievedObjects[1]);
+    }
+
+    @Test
+    public void coerceParamsNotConverted() {
+        Object item = "TESTED_OBJECT";
+        Object value = Collections.singleton(item);
+        Object[] actualParams1 = {value, "NOT_DATE"};
+        Optional<Object[]> retrieved = CoerceUtil.coerceParams(Set.class, 
BigDecimal.class, actualParams1, 0);
+        assertNotNull(retrieved);
+        assertTrue(retrieved.isEmpty());
+
+        value = LocalDate.now();
+        Object[] actualParams2 = {value, "NOT_DATE"};
+        retrieved = CoerceUtil.coerceParams(LocalDate.class, String.class, 
actualParams2, 0);
+        assertNotNull(retrieved);
+        assertTrue(retrieved.isEmpty());
+    }
+
+    @Test
+    public void actualCoerceParameterToDateTimeConverted() {
+        Object value = LocalDate.now();
+        Object retrieved = 
CoerceUtil.actualCoerceParameter(BuiltInType.DATE_TIME, value);
+        assertNotNull(retrieved);
+        assertTrue(retrieved instanceof ZonedDateTime);
+        ZonedDateTime zdtRetrieved = (ZonedDateTime) retrieved;
+        assertEquals(value, zdtRetrieved.toLocalDate());
+        assertEquals(ZoneOffset.UTC, zdtRetrieved.getOffset());
+        assertEquals(0, zdtRetrieved.getHour());
+        assertEquals(0, zdtRetrieved.getMinute());
+        assertEquals(0, zdtRetrieved.getSecond());
+    }
+
+    @Test
+    public void actualCoerceParameterNotConverted() {
+        Object value = "TEST_OBJECT";
+        Object retrieved = 
CoerceUtil.actualCoerceParameter(BuiltInType.DATE_TIME, value);
+        assertNotNull(retrieved);
+        assertEquals(value, retrieved);
+
+        value = LocalDate.now();
+        retrieved = CoerceUtil.actualCoerceParameter(BuiltInType.DATE, value);
+        assertNotNull(retrieved);
+        assertEquals(value, retrieved);
+    }
+
+    @Test
+    public void actualCoerceParams() {
+        Object value = LocalDate.now();
+        Object[] actualParams = {value, "NOT_DATE"};
+        Object coercedValue = BigDecimal.valueOf(1L);
+        Object[] retrieved = CoerceUtil.actualCoerceParams(actualParams, 
coercedValue, 0);
+        assertNotNull(retrieved);
+        assertEquals(actualParams.length, retrieved.length);
+        assertEquals(coercedValue, retrieved[0]);
+        assertEquals(actualParams[1], retrieved[1]);
+    }
+
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to