gitgabrio commented on code in PR #6776:
URL:
https://github.com/apache/incubator-kie-drools/pull/6776#discussion_r3526974433
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDecisionServiceEvaluator.java:
##########
@@ -22,14 +22,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
import org.kie.dmn.api.core.DMNDecisionResult;
import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.api.core.DMNMessage.Severity;
import org.kie.dmn.api.core.DMNModel;
import org.kie.dmn.api.core.DMNResult;
import org.kie.dmn.api.core.DMNRuntime;
+import org.kie.dmn.api.core.DMNType;
+import org.kie.dmn.api.core.ast.DecisionNode;
Review Comment:
HI @AthiraHari77 IINW, this import is unneeded
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDecisionServiceEvaluator.java:
##########
@@ -84,8 +93,9 @@ public EvaluatorResult evaluate(DMNRuntimeEventManager
eventManager, DMNResult r
}
}
boolean typeCheck = ((DMNRuntimeImpl)
eventManager.getRuntime()).performRuntimeTypeCheck(result.getModel());
+ Object finalResult = decisionIDs.size() == 1 ?
ctx.values().iterator().next() : ctx;
if (typeCheck) {
- Object c = DMNRuntimeUtils.coerceUsingType(decisionIDs.size() == 1
? ctx.values().iterator().next() : ctx,
+ Object c = DMNRuntimeUtils.coerceUsingType(finalResult,
Review Comment:
@AthiraHari77
I know that code was already there, but the name of this method:
`DMNRuntimeUtils.coerceUsingType` is unclear and, keeping in mind we also
have `CoerceUtil.coerceValue` , the overall result is pretty confusing.
`DMNRuntimeUtils.coerceUsingType` actually deals only with `Collections`:
could you please verify that and, eventually, rename it to make that clearer ?
Just to reduce a bit tech debts while we found them. Thanks!
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java:
##########
@@ -216,115 +219,166 @@ private void
reportReferenceError(DecisionServiceNodeImpl ni, DMNModelImpl model
ni.getName());
}
- private void checkFnConsistency(DMNModelImpl model,
DecisionServiceNodeImpl ni, DMNType type, List<DecisionNode> outputDecisions) {
- SimpleFnTypeImpl fnType = ((SimpleFnTypeImpl) type);
- FunctionItem fi = fnType.getFunctionItem();
- if (fi.getParameters().size() != ni.getInputParameters().size()) {
+ private void validateDecisionServiceFunctionSignature(DMNModelImpl model,
DecisionServiceNodeImpl decisionServiceNode, DMNType
decisionServiceFunctionType, List<DecisionNode> outputDecisions) {
+ SimpleFnTypeImpl functionType = ((SimpleFnTypeImpl)
decisionServiceFunctionType);
+ FunctionItem functionItem = functionType.getFunctionItem();
+ if (functionItem.getParameters().size() !=
decisionServiceNode.getInputParameters().size()) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_COUNT_MISMATCH_COMPILING,
- ni.getName(),
- fi.getParameters().size(),
- ni.getInputParameters().size());
+ decisionServiceNode.getName(),
+ functionItem.getParameters().size(),
+
decisionServiceNode.getInputParameters().size());
return;
}
- for (int i = 0; i < fi.getParameters().size(); i++) {
- InformationItem fiII = fi.getParameters().get(i);
- String fpName =
ni.getInputParameters().keySet().stream().skip(i).findFirst().orElse(null);
- if (!fiII.getName().equals(fpName)) {
- List<String> fiParamNames =
fi.getParameters().stream().map(InformationItem::getName).collect(Collectors.toList());
- List<String> funcDefParamNames =
ni.getInputParameters().keySet().stream().collect(Collectors.toList());
+ for (int i = 0; i < functionItem.getParameters().size(); i++) {
+ InformationItem functionParameter =
functionItem.getParameters().get(i);
+ String functionParameterName =
decisionServiceNode.getInputParameters().keySet().stream().skip(i).findFirst().orElse(null);
+ if (!functionParameter.getName().equals(functionParameterName)) {
+ List<String> functionItemParamNames =
functionItem.getParameters().stream().map(InformationItem::getName).collect(Collectors.toList());
+ List<String> decisionServiceParamNames =
decisionServiceNode.getInputParameters().keySet().stream().collect(Collectors.toList());
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_NAMES_MISMATCH_COMPILING,
- ni.getName(),
- fiParamNames,
- funcDefParamNames);
+ decisionServiceNode.getName(),
+ functionItemParamNames,
+ decisionServiceParamNames);
return;
}
- QName fiQname = fiII.getTypeRef();
- QName fdQname = null;
- DMNNode fpDMNNode = ni.getInputParameters().get(fpName);
- if (fpDMNNode instanceof InputDataNodeImpl) {
- fdQname = ((InputDataNodeImpl)
fpDMNNode).getInputData().getVariable().getTypeRef();
- } else if (fpDMNNode instanceof DecisionNodeImpl) {
- fdQname = ((DecisionNodeImpl)
fpDMNNode).getDecision().getVariable().getTypeRef();
+ QName functionParameterTypeRef = functionParameter.getTypeRef();
+ QName decisionServiceParameterTypeRef = null;
+ DMNNode inputParameterNode =
decisionServiceNode.getInputParameters().get(functionParameterName);
+ if (inputParameterNode instanceof InputDataNodeImpl) {
+ decisionServiceParameterTypeRef = ((InputDataNodeImpl)
inputParameterNode).getInputData().getVariable().getTypeRef();
+ } else if (inputParameterNode instanceof DecisionNodeImpl) {
+ decisionServiceParameterTypeRef = ((DecisionNodeImpl)
inputParameterNode).getDecision().getVariable().getTypeRef();
}
- if (fiQname != null && fdQname != null &&
!fiQname.equals(fdQname)) {
+ if (functionParameterTypeRef != null &&
decisionServiceParameterTypeRef != null &&
!functionParameterTypeRef.equals(decisionServiceParameterTypeRef)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiII.getName(),
- fiQname,
- fdQname);
+ decisionServiceNode.getName(),
+ functionParameter.getName(),
+ functionParameterTypeRef,
+ decisionServiceParameterTypeRef);
}
}
- QName fiReturnType = fi.getOutputTypeRef();
- if (ni.getDecisionService().getOutputDecision().size() == 1) {
- QName fdReturnType =
outputDecisions.get(0).getDecision().getVariable().getTypeRef();
- if (fiReturnType != null && fdReturnType != null &&
!fiReturnType.equals(fdReturnType)) {
+ QName functionReturnTypeRef = functionItem.getOutputTypeRef();
+ if
(decisionServiceNode.getDecisionService().getOutputDecision().size() == 1) {
+ QName outputDecisionReturnTypeRef =
outputDecisions.get(0).getDecision().getVariable().getTypeRef();
+ if (functionReturnTypeRef != null && outputDecisionReturnTypeRef
!= null && !functionReturnTypeRef.equals(outputDecisionReturnTypeRef) &&
!isReturnTypeCollectionCompatible(functionReturnTypeRef,
outputDecisionReturnTypeRef, model)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiReturnType,
- fdReturnType);
+ decisionServiceNode.getName(),
+ functionReturnTypeRef,
+ outputDecisionReturnTypeRef);
}
- } else if (ni.getDecisionService().getOutputDecision().size() > 1) {
- final Function<QName, QName> lookupFn = (in) ->
NamespaceUtil.getNamespaceAndName(ni.getDecisionService(),
model.getImportAliasesForNS(), in, model.getNamespace());
- LinkedHashMap<String, QName> fdComposite = new LinkedHashMap<>();
- for (DecisionNode dn : outputDecisions) {
- fdComposite.put(dn.getName(),
lookupFn.apply(dn.getDecision().getVariable().getTypeRef()));
+ } else if
(decisionServiceNode.getDecisionService().getOutputDecision().size() > 1) {
+ final Function<QName, QName> namespaceQNameLookup = (qname) ->
NamespaceUtil.getNamespaceAndName(decisionServiceNode.getDecisionService(),
model.getImportAliasesForNS(), qname, model.getNamespace());
+ LinkedHashMap<String, QName> decisionServiceCompositeType = new
LinkedHashMap<>();
+ for (DecisionNode decisionNode : outputDecisions) {
+ decisionServiceCompositeType.put(decisionNode.getName(),
namespaceQNameLookup.apply(decisionNode.getDecision().getVariable().getTypeRef()));
}
- final QName lookup = lookupFn.apply(fiReturnType);
- Optional<ItemDefNodeImpl> composite =
model.getItemDefinitions().stream().filter(id ->
id.getModelNamespace().equals(lookup.getNamespaceURI()) &&
id.getName().equals(lookup.getLocalPart())).map(ItemDefNodeImpl.class::cast).findFirst();
- if (composite.isEmpty()) {
+ final QName resolvedFunctionReturnTypeRef =
namespaceQNameLookup.apply(functionReturnTypeRef);
+ Optional<ItemDefNodeImpl> matchedItemDefNode =
model.getItemDefinitions().stream().filter(id ->
id.getModelNamespace().equals(resolvedFunctionReturnTypeRef.getNamespaceURI())
&&
id.getName().equals(resolvedFunctionReturnTypeRef.getLocalPart())).map(ItemDefNodeImpl.class::cast).findFirst();
+ if (matchedItemDefNode.isEmpty()) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- lookup,
- fdComposite);
+ decisionServiceNode.getName(),
+ resolvedFunctionReturnTypeRef,
+ decisionServiceCompositeType);
return;
}
- LinkedHashMap<String, QName> fiComposite = new LinkedHashMap<>();
- for (ItemDefinition ic :
composite.get().getItemDef().getItemComponent()) {
- fiComposite.put(ic.getName(), lookupFn.apply(ic.getTypeRef()));
+ LinkedHashMap<String, QName> functionCompositeType = new
LinkedHashMap<>();
+ for (ItemDefinition itemDefinition :
matchedItemDefNode.get().getItemDef().getItemComponent()) {
+ functionCompositeType.put(itemDefinition.getName(),
namespaceQNameLookup.apply(itemDefinition.getTypeRef()));
}
- if (!fiComposite.equals(fdComposite)) {
+ if (!functionCompositeType.equals(decisionServiceCompositeType)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiComposite,
- fdComposite);
+ decisionServiceNode.getName(),
+ functionCompositeType,
+ decisionServiceCompositeType);
}
}
}
+ static boolean isReturnTypeCollectionCompatible(QName
functionReturnTypeRef, QName outputDecisionReturnTypeRef, DMNModelImpl model) {
Review Comment:
Hi @AthiraHari77
Those two static methods IMO should go to some common utility class, since
there behavior is very "generic" and probably already needed elsewhere.
Maybe inside `DMNRuntimeUtils` ? Or maybe there is already some "util" class
that deals with similar implementations ?
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java:
##########
@@ -216,115 +219,166 @@ private void
reportReferenceError(DecisionServiceNodeImpl ni, DMNModelImpl model
ni.getName());
}
- private void checkFnConsistency(DMNModelImpl model,
DecisionServiceNodeImpl ni, DMNType type, List<DecisionNode> outputDecisions) {
- SimpleFnTypeImpl fnType = ((SimpleFnTypeImpl) type);
- FunctionItem fi = fnType.getFunctionItem();
- if (fi.getParameters().size() != ni.getInputParameters().size()) {
+ private void validateDecisionServiceFunctionSignature(DMNModelImpl model,
DecisionServiceNodeImpl decisionServiceNode, DMNType
decisionServiceFunctionType, List<DecisionNode> outputDecisions) {
Review Comment:
👍 🙏 ❤️
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and
time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and
time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("",
"date and time"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.DATE_TIME);
+ assertThat(result.isCollection()).isFalse();
+ }
+
+ @Test
+ void resolveDMNType_listBuiltInIsMarkedAsCollection() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and
time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
Review Comment:
@AthiraHari77
The need of those mocks (that actually creates a "fake" implementation) is
related to that implementation ->
```java
static DMNType resolveDMNType(QName typeRef, DMNModelImpl model) {
DMNType type =
model.getTypeRegistry().resolveType(model.getNamespace(),
typeRef.getLocalPart());
if (type == null) {
BuiltInType builtInType =
resolveBuiltInType(typeRef.getLocalPart());
if (builtInType != null) {
boolean isCollection = (builtInType == BuiltInType.LIST);
type = new SimpleTypeImpl(
model.getNamespace(),
builtInType.getName(),
null,
isCollection,
null,
null,
null,
builtInType
);
}
}
return type;
}
```
What this test is about is the `type==null` branch of execution but, since
it is embedded inside the `DMNType resolveDMNTYpe`, hence the need of (slightly
contrived) mocking.
Extracting the content of `type==null` branch to a specific method, would
reduce the "cyclomatic complexity" of the method ( 😄 ) and simplify testing
it, removing the need of "mocks".
(In general terms, lot of time mocks are always a smell of something not
perfectly encapsulated).
Am I clear ? Does this make sense ?
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java:
##########
@@ -216,115 +219,166 @@ private void
reportReferenceError(DecisionServiceNodeImpl ni, DMNModelImpl model
ni.getName());
}
- private void checkFnConsistency(DMNModelImpl model,
DecisionServiceNodeImpl ni, DMNType type, List<DecisionNode> outputDecisions) {
- SimpleFnTypeImpl fnType = ((SimpleFnTypeImpl) type);
- FunctionItem fi = fnType.getFunctionItem();
- if (fi.getParameters().size() != ni.getInputParameters().size()) {
+ private void validateDecisionServiceFunctionSignature(DMNModelImpl model,
DecisionServiceNodeImpl decisionServiceNode, DMNType
decisionServiceFunctionType, List<DecisionNode> outputDecisions) {
+ SimpleFnTypeImpl functionType = ((SimpleFnTypeImpl)
decisionServiceFunctionType);
+ FunctionItem functionItem = functionType.getFunctionItem();
+ if (functionItem.getParameters().size() !=
decisionServiceNode.getInputParameters().size()) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_COUNT_MISMATCH_COMPILING,
- ni.getName(),
- fi.getParameters().size(),
- ni.getInputParameters().size());
+ decisionServiceNode.getName(),
+ functionItem.getParameters().size(),
+
decisionServiceNode.getInputParameters().size());
return;
}
- for (int i = 0; i < fi.getParameters().size(); i++) {
- InformationItem fiII = fi.getParameters().get(i);
- String fpName =
ni.getInputParameters().keySet().stream().skip(i).findFirst().orElse(null);
- if (!fiII.getName().equals(fpName)) {
- List<String> fiParamNames =
fi.getParameters().stream().map(InformationItem::getName).collect(Collectors.toList());
- List<String> funcDefParamNames =
ni.getInputParameters().keySet().stream().collect(Collectors.toList());
+ for (int i = 0; i < functionItem.getParameters().size(); i++) {
+ InformationItem functionParameter =
functionItem.getParameters().get(i);
+ String functionParameterName =
decisionServiceNode.getInputParameters().keySet().stream().skip(i).findFirst().orElse(null);
+ if (!functionParameter.getName().equals(functionParameterName)) {
+ List<String> functionItemParamNames =
functionItem.getParameters().stream().map(InformationItem::getName).collect(Collectors.toList());
+ List<String> decisionServiceParamNames =
decisionServiceNode.getInputParameters().keySet().stream().collect(Collectors.toList());
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_NAMES_MISMATCH_COMPILING,
- ni.getName(),
- fiParamNames,
- funcDefParamNames);
+ decisionServiceNode.getName(),
+ functionItemParamNames,
+ decisionServiceParamNames);
return;
}
- QName fiQname = fiII.getTypeRef();
- QName fdQname = null;
- DMNNode fpDMNNode = ni.getInputParameters().get(fpName);
- if (fpDMNNode instanceof InputDataNodeImpl) {
- fdQname = ((InputDataNodeImpl)
fpDMNNode).getInputData().getVariable().getTypeRef();
- } else if (fpDMNNode instanceof DecisionNodeImpl) {
- fdQname = ((DecisionNodeImpl)
fpDMNNode).getDecision().getVariable().getTypeRef();
+ QName functionParameterTypeRef = functionParameter.getTypeRef();
+ QName decisionServiceParameterTypeRef = null;
+ DMNNode inputParameterNode =
decisionServiceNode.getInputParameters().get(functionParameterName);
+ if (inputParameterNode instanceof InputDataNodeImpl) {
+ decisionServiceParameterTypeRef = ((InputDataNodeImpl)
inputParameterNode).getInputData().getVariable().getTypeRef();
+ } else if (inputParameterNode instanceof DecisionNodeImpl) {
+ decisionServiceParameterTypeRef = ((DecisionNodeImpl)
inputParameterNode).getDecision().getVariable().getTypeRef();
}
- if (fiQname != null && fdQname != null &&
!fiQname.equals(fdQname)) {
+ if (functionParameterTypeRef != null &&
decisionServiceParameterTypeRef != null &&
!functionParameterTypeRef.equals(decisionServiceParameterTypeRef)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiII.getName(),
- fiQname,
- fdQname);
+ decisionServiceNode.getName(),
+ functionParameter.getName(),
+ functionParameterTypeRef,
+ decisionServiceParameterTypeRef);
}
}
- QName fiReturnType = fi.getOutputTypeRef();
- if (ni.getDecisionService().getOutputDecision().size() == 1) {
- QName fdReturnType =
outputDecisions.get(0).getDecision().getVariable().getTypeRef();
- if (fiReturnType != null && fdReturnType != null &&
!fiReturnType.equals(fdReturnType)) {
+ QName functionReturnTypeRef = functionItem.getOutputTypeRef();
+ if
(decisionServiceNode.getDecisionService().getOutputDecision().size() == 1) {
+ QName outputDecisionReturnTypeRef =
outputDecisions.get(0).getDecision().getVariable().getTypeRef();
+ if (functionReturnTypeRef != null && outputDecisionReturnTypeRef
!= null && !functionReturnTypeRef.equals(outputDecisionReturnTypeRef) &&
!isReturnTypeCollectionCompatible(functionReturnTypeRef,
outputDecisionReturnTypeRef, model)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiReturnType,
- fdReturnType);
+ decisionServiceNode.getName(),
+ functionReturnTypeRef,
+ outputDecisionReturnTypeRef);
}
- } else if (ni.getDecisionService().getOutputDecision().size() > 1) {
- final Function<QName, QName> lookupFn = (in) ->
NamespaceUtil.getNamespaceAndName(ni.getDecisionService(),
model.getImportAliasesForNS(), in, model.getNamespace());
- LinkedHashMap<String, QName> fdComposite = new LinkedHashMap<>();
- for (DecisionNode dn : outputDecisions) {
- fdComposite.put(dn.getName(),
lookupFn.apply(dn.getDecision().getVariable().getTypeRef()));
+ } else if
(decisionServiceNode.getDecisionService().getOutputDecision().size() > 1) {
+ final Function<QName, QName> namespaceQNameLookup = (qname) ->
NamespaceUtil.getNamespaceAndName(decisionServiceNode.getDecisionService(),
model.getImportAliasesForNS(), qname, model.getNamespace());
+ LinkedHashMap<String, QName> decisionServiceCompositeType = new
LinkedHashMap<>();
+ for (DecisionNode decisionNode : outputDecisions) {
+ decisionServiceCompositeType.put(decisionNode.getName(),
namespaceQNameLookup.apply(decisionNode.getDecision().getVariable().getTypeRef()));
}
- final QName lookup = lookupFn.apply(fiReturnType);
- Optional<ItemDefNodeImpl> composite =
model.getItemDefinitions().stream().filter(id ->
id.getModelNamespace().equals(lookup.getNamespaceURI()) &&
id.getName().equals(lookup.getLocalPart())).map(ItemDefNodeImpl.class::cast).findFirst();
- if (composite.isEmpty()) {
+ final QName resolvedFunctionReturnTypeRef =
namespaceQNameLookup.apply(functionReturnTypeRef);
+ Optional<ItemDefNodeImpl> matchedItemDefNode =
model.getItemDefinitions().stream().filter(id ->
id.getModelNamespace().equals(resolvedFunctionReturnTypeRef.getNamespaceURI())
&&
id.getName().equals(resolvedFunctionReturnTypeRef.getLocalPart())).map(ItemDefNodeImpl.class::cast).findFirst();
+ if (matchedItemDefNode.isEmpty()) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- lookup,
- fdComposite);
+ decisionServiceNode.getName(),
+ resolvedFunctionReturnTypeRef,
+ decisionServiceCompositeType);
return;
}
- LinkedHashMap<String, QName> fiComposite = new LinkedHashMap<>();
- for (ItemDefinition ic :
composite.get().getItemDef().getItemComponent()) {
- fiComposite.put(ic.getName(), lookupFn.apply(ic.getTypeRef()));
+ LinkedHashMap<String, QName> functionCompositeType = new
LinkedHashMap<>();
+ for (ItemDefinition itemDefinition :
matchedItemDefNode.get().getItemDef().getItemComponent()) {
+ functionCompositeType.put(itemDefinition.getName(),
namespaceQNameLookup.apply(itemDefinition.getTypeRef()));
}
- if (!fiComposite.equals(fdComposite)) {
+ if (!functionCompositeType.equals(decisionServiceCompositeType)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiComposite,
- fdComposite);
+ decisionServiceNode.getName(),
+ functionCompositeType,
+ decisionServiceCompositeType);
}
}
}
+ static boolean isReturnTypeCollectionCompatible(QName
functionReturnTypeRef, QName outputDecisionReturnTypeRef, DMNModelImpl model) {
+ DMNType decisionServiceOutputType =
resolveDMNType(functionReturnTypeRef, model);
+ DMNType decisionOutputType =
resolveDMNType(outputDecisionReturnTypeRef, model);
+
+ if (!decisionServiceOutputType.isCollection() &&
decisionOutputType.isCollection()) {
+ DMNType outputDecisionElementType =
decisionOutputType.getBaseType();
+ return outputDecisionElementType == null ||
DMNTypeUtils.getFEELBuiltInType(outputDecisionElementType)
+ ==
DMNTypeUtils.getFEELBuiltInType(decisionServiceOutputType);
+ }
+ if (decisionServiceOutputType.isCollection() &&
!decisionOutputType.isCollection()) {
+ DMNType decisionServiceElementType =
decisionServiceOutputType.getBaseType();
+ return decisionServiceElementType != null &&
DMNTypeUtils.getFEELBuiltInType(decisionServiceElementType)
+ == DMNTypeUtils.getFEELBuiltInType(decisionOutputType);
+ }
+ return decisionServiceOutputType instanceof SimpleTypeImpl
decisionServiceSimpleType && decisionServiceSimpleType.getFeelType() ==
BuiltInType.DATE_TIME &&
+ decisionOutputType instanceof SimpleTypeImpl
decisionOutputSimpleType && decisionOutputSimpleType.getFeelType() ==
BuiltInType.DATE;
+ }
+
+ static DMNType resolveDMNType(QName typeRef, DMNModelImpl model) {
+ DMNType type =
model.getTypeRegistry().resolveType(model.getNamespace(),
typeRef.getLocalPart());
+ if (type == null) {
+ BuiltInType builtInType =
resolveBuiltInType(typeRef.getLocalPart());
+ if (builtInType != null) {
+ boolean isCollection = (builtInType == BuiltInType.LIST);
+ type = new SimpleTypeImpl(
+ model.getNamespace(),
+ builtInType.getName(),
+ null,
+ isCollection,
+ null,
+ null,
+ null,
+ builtInType
+ );
+ }
+ }
+ return type;
+ }
+
+ static BuiltInType resolveBuiltInType(String name) {
Review Comment:
See comment above. I've the impression that this functionality is already
implemented somewhere, but I can't recall where 🤔 (I may be wrong, of course)
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and
time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("",
"date and time"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.DATE_TIME);
+ assertThat(result.isCollection()).isFalse();
+ }
+
+ @Test
+ void resolveDMNType_listBuiltInIsMarkedAsCollection() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("",
"list"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.LIST);
+ assertThat(result.isCollection()).isTrue();
+ }
+
+ @Test
+ void resolveDMNType_unknownNameReturnsNull() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.resolveDMNType(new QName("",
"not-a-type"), model)).isNull();
+ }
+
+ // fi=scalar "string", fd=collection "tDateList" (base=date) — bases
differ → false
+ @Test
+ void isReturnTypeCollectionCompatible_incompatibleType() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false,
null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null,
true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv ->
"tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "string"), new QName(ns, "tDateList"),
model)).isFalse();
+ }
+
+ // fi=scalar "date", fd=collection "tDateList" (base=date) — same base →
true
+ @Test
+ void isReturnTypeCollectionCompatible_compatibleType() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false,
null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null,
true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv ->
"tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "date"), new QName(ns, "tDateList"),
model)).isTrue();
+ }
+
+
+ // fi=collection "tDateList" (base=date), fd=scalar "date" — compatible →
true
+ @Test
+ void
isReturnTypeCollectionCompatible_collectionFi_scalarFd_compatibleBase() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false,
null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null,
true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv ->
"tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "tDateList"), new QName(ns, "date"),
model)).isTrue();
+ }
+
+
+ // fi="date and time", fd="date" — date-to-dateTime coercion pattern → true
+ @Test
+ void isReturnTypeCollectionCompatible_dateTimeFi_dateFd_compatible() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and
time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("",
"date and time"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.DATE_TIME);
+ assertThat(result.isCollection()).isFalse();
+ }
+
+ @Test
+ void resolveDMNType_listBuiltInIsMarkedAsCollection() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("",
"list"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.LIST);
+ assertThat(result.isCollection()).isTrue();
+ }
+
+ @Test
+ void resolveDMNType_unknownNameReturnsNull() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
##########
kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/decisionservices/DecisionServiceImplicitConversions.dmn:
##########
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
Review Comment:
HI @AthiraHari77
Plkease, do not add new dmn models outside `kie-dmn-test-resources`.
Our approach is to have all testing DMN inside `kie-dmn-test-resources` and
then refer to them properly.
Thanks!
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and
time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+
assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("",
"date and time"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.DATE_TIME);
+ assertThat(result.isCollection()).isFalse();
+ }
+
+ @Test
+ void resolveDMNType_listBuiltInIsMarkedAsCollection() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("",
"list"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl)
result).getFeelType()).isEqualTo(BuiltInType.LIST);
+ assertThat(result.isCollection()).isTrue();
+ }
+
+ @Test
+ void resolveDMNType_unknownNameReturnsNull() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.resolveDMNType(new QName("",
"not-a-type"), model)).isNull();
+ }
+
+ // fi=scalar "string", fd=collection "tDateList" (base=date) — bases
differ → false
+ @Test
+ void isReturnTypeCollectionCompatible_incompatibleType() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false,
null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null,
true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv ->
"tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "string"), new QName(ns, "tDateList"),
model)).isFalse();
+ }
+
+ // fi=scalar "date", fd=collection "tDateList" (base=date) — same base →
true
+ @Test
+ void isReturnTypeCollectionCompatible_compatibleType() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false,
null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null,
true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv ->
"tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "date"), new QName(ns, "tDateList"),
model)).isTrue();
+ }
+
+
+ // fi=collection "tDateList" (base=date), fd=scalar "date" — compatible →
true
+ @Test
+ void
isReturnTypeCollectionCompatible_collectionFi_scalarFd_compatibleBase() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false,
null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null,
true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv ->
"tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "tDateList"), new QName(ns, "date"),
model)).isTrue();
+ }
+
+
+ // fi="date and time", fd="date" — date-to-dateTime coercion pattern → true
+ @Test
+ void isReturnTypeCollectionCompatible_dateTimeFi_dateFd_compatible() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName("", "date and time"), new QName("", "date"),
model)).isTrue();
+ }
+
+ // fi="date", fd="date and time" — order matters → false
+ @Test
+ void isReturnTypeCollectionCompatible_dateFi_dateTimeFd_incompatible() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]