Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
antvaset committed Sep 10, 2024
1 parent ecf68e2 commit c09aa55
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,30 +79,11 @@ protected static FunctionDef resolveFunctionRef(State state, FunctionRef functio

var functionDefs = resolveFunctionRef(state, name, arguments, signature);

final List<? extends Object> types = signature.isEmpty() ? arguments : signature;

if (functionDefs.isEmpty()) {
throw new CqlException(String.format(
"Could not resolve call to operator '%s(%s)' in library '%s'.",
name,
getUnresolvedMessage(state, types, name),
state.getCurrentLibrary().getIdentifier().getId()));
}

if (functionDefs.size() == 1) {
// Normal case
return functionDefs.get(0);
}

throw new CqlException(String.format(
"Ambiguous call to operator '%s(%s)' in library '%s'.",
name,
getUnresolvedMessage(state, types, name),
state.getCurrentLibrary().getIdentifier().getId()));
return pickFunctionDef(state, name, arguments, signature, functionDefs);
}

private static List<FunctionDef> resolveFunctionRef(
State state, final String name, final List<Object> arguments, final List<TypeSpecifier> signature) {
static List<FunctionDef> resolveFunctionRef(
State state, String name, List<Object> arguments, List<TypeSpecifier> signature) {
var namedDefs = Libraries.getFunctionDefs(name, state.getCurrentLibrary());

// If the function ref includes a signature, use the signature to find the matching function defs
Expand All @@ -121,15 +102,15 @@ private static List<FunctionDef> resolveFunctionRef(
.collect(Collectors.toList());
}

private static boolean functionDefOperandsSignatureEqual(FunctionDef functionDef, List<TypeSpecifier> signature) {
static boolean functionDefOperandsSignatureEqual(FunctionDef functionDef, List<TypeSpecifier> signature) {
var operands = functionDef.getOperand();

return operands.size() == signature.size()
&& IntStream.range(0, operands.size())
.allMatch(i -> operandDefTypeSpecifierEqual(operands.get(i), signature.get(i)));
}

private static boolean operandDefTypeSpecifierEqual(OperandDef operandDef, TypeSpecifier typeSpecifier) {
static boolean operandDefTypeSpecifierEqual(OperandDef operandDef, TypeSpecifier typeSpecifier) {
// An operand def can have an operandTypeSpecifier or operandType

var operandDefOperandTypeSpecifier = operandDef.getOperandTypeSpecifier();
Expand All @@ -145,7 +126,35 @@ private static boolean operandDefTypeSpecifierEqual(OperandDef operandDef, TypeS
return false;
}

private static String getUnresolvedMessage(State state, List<? extends Object> arguments, String name) {
static FunctionDef pickFunctionDef(
State state,
String name,
List<Object> arguments,
List<TypeSpecifier> signature,
List<FunctionDef> functionDefs) {
var types = signature.isEmpty() ? arguments : signature;

if (functionDefs.isEmpty()) {
throw new CqlException(String.format(
"Could not resolve call to operator '%s(%s)' in library '%s'.",
name,
typesToString(state, types),
state.getCurrentLibrary().getIdentifier().getId()));
}

if (functionDefs.size() == 1) {
// Normal case
return functionDefs.get(0);
}

throw new CqlException(String.format(
"Ambiguous call to operator '%s(%s)' in library '%s'.",
name,
typesToString(state, types),
state.getCurrentLibrary().getIdentifier().getId()));
}

static String typesToString(State state, List<? extends Object> arguments) {
StringBuilder argStr = new StringBuilder();
if (arguments != null) {
arguments.forEach(a -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package org.opencds.cqf.cql.engine.execution;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.cqframework.cql.cql2elm.CqlCompilerOptions;
import org.cqframework.cql.cql2elm.LibraryBuilder;
import org.hl7.elm.r1.VersionedIdentifier;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.opencds.cqf.cql.engine.exception.CqlException;

@SuppressWarnings("removal")
class CqlListDistinguishedOverloadsTest extends CqlTestBase {
Expand All @@ -13,9 +16,17 @@ class CqlListDistinguishedOverloadsTest extends CqlTestBase {
new VersionedIdentifier().withId("CqlListDistinguishedOverloads");

@Test
@Disabled("There's a bug in the cql engine that is causing it to select the wrong function overload at runtime")
void list_overload() {
var value = engine.expression(library, "Test").value();
var compilerOptions = CqlCompilerOptions.defaultOptions();

var engine1 = getEngine(compilerOptions.withSignatureLevel(LibraryBuilder.SignatureLevel.Overloads));
var value = engine1.expression(library, "Test").value();
assertEquals("1, 2, 3, 4, 5", value);

var engine2 = getEngine(compilerOptions.withSignatureLevel(LibraryBuilder.SignatureLevel.None));
var cqlException = assertThrows(CqlException.class, () -> engine2.expression(library, "Test"));
assertEquals(
"Ambiguous call to operator 'toString(java.util.List)' in library 'CqlListDistinguishedOverloads'.",
cqlException.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ define function toString(value List<Code>):
else Combine((value V return toString(V)), ', ')

// This is the function that _should_ be selected at runtime for the
// List distinguised overloads test. At the time this CQL was written,
// The engine had a bug that was selecting the List<Code> overload
// List distinguished overloads test. The engine currently cannot
// distinguish between the List<Integer> and List<Code> overloads
// (and throws the error "Ambiguous call to function 'toString'")
// unless the library is compiled with signature level set to
// Overloads or All.
// See also https://github.com/cqframework/clinical_quality_language/issues/1408.
define function toString(value List<Integer>):
if value is null
then 'null'
Expand Down

0 comments on commit c09aa55

Please sign in to comment.