blob: 0c8ea1b71fab3c26f20af7cff75ee27cd0398819 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.math.expr;
import com.google.common.collect.ImmutableMap;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.testing.InitializedNullHandlingTest;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.util.Map;
public class OutputTypeTest extends InitializedNullHandlingTest
{
private final Expr.InputBindingInspector inspector = inspectorFromMap(
ImmutableMap.<String, ExprType>builder().put("x", ExprType.STRING)
.put("x_", ExprType.STRING)
.put("y", ExprType.LONG)
.put("y_", ExprType.LONG)
.put("z", ExprType.DOUBLE)
.put("z_", ExprType.DOUBLE)
.put("a", ExprType.STRING_ARRAY)
.put("a_", ExprType.STRING_ARRAY)
.put("b", ExprType.LONG_ARRAY)
.put("b_", ExprType.LONG_ARRAY)
.put("c", ExprType.DOUBLE_ARRAY)
.put("c_", ExprType.DOUBLE_ARRAY)
.build()
);
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testConstantsAndIdentifiers()
{
assertOutputType("'hello'", inspector, ExprType.STRING);
assertOutputType("23", inspector, ExprType.LONG);
assertOutputType("3.2", inspector, ExprType.DOUBLE);
assertOutputType("['a', 'b']", inspector, ExprType.STRING_ARRAY);
assertOutputType("[1,2,3]", inspector, ExprType.LONG_ARRAY);
assertOutputType("[1.0]", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("x", inspector, ExprType.STRING);
assertOutputType("y", inspector, ExprType.LONG);
assertOutputType("z", inspector, ExprType.DOUBLE);
assertOutputType("a", inspector, ExprType.STRING_ARRAY);
assertOutputType("b", inspector, ExprType.LONG_ARRAY);
assertOutputType("c", inspector, ExprType.DOUBLE_ARRAY);
}
@Test
public void testUnaryOperators()
{
assertOutputType("-1", inspector, ExprType.LONG);
assertOutputType("-1.1", inspector, ExprType.DOUBLE);
assertOutputType("-y", inspector, ExprType.LONG);
assertOutputType("-z", inspector, ExprType.DOUBLE);
assertOutputType("!'true'", inspector, ExprType.LONG);
assertOutputType("!1", inspector, ExprType.LONG);
assertOutputType("!1.1", inspector, ExprType.DOUBLE);
assertOutputType("!x", inspector, ExprType.LONG);
assertOutputType("!y", inspector, ExprType.LONG);
assertOutputType("!z", inspector, ExprType.DOUBLE);
}
@Test
public void testBinaryMathOperators()
{
assertOutputType("1+1", inspector, ExprType.LONG);
assertOutputType("1-1", inspector, ExprType.LONG);
assertOutputType("1*1", inspector, ExprType.LONG);
assertOutputType("1/1", inspector, ExprType.LONG);
assertOutputType("1^1", inspector, ExprType.LONG);
assertOutputType("1%1", inspector, ExprType.LONG);
assertOutputType("y+y_", inspector, ExprType.LONG);
assertOutputType("y-y_", inspector, ExprType.LONG);
assertOutputType("y*y_", inspector, ExprType.LONG);
assertOutputType("y/y_", inspector, ExprType.LONG);
assertOutputType("y^y_", inspector, ExprType.LONG);
assertOutputType("y%y_", inspector, ExprType.LONG);
assertOutputType("y+z", inspector, ExprType.DOUBLE);
assertOutputType("y-z", inspector, ExprType.DOUBLE);
assertOutputType("y*z", inspector, ExprType.DOUBLE);
assertOutputType("y/z", inspector, ExprType.DOUBLE);
assertOutputType("y^z", inspector, ExprType.DOUBLE);
assertOutputType("y%z", inspector, ExprType.DOUBLE);
assertOutputType("z+z_", inspector, ExprType.DOUBLE);
assertOutputType("z-z_", inspector, ExprType.DOUBLE);
assertOutputType("z*z_", inspector, ExprType.DOUBLE);
assertOutputType("z/z_", inspector, ExprType.DOUBLE);
assertOutputType("z^z_", inspector, ExprType.DOUBLE);
assertOutputType("z%z_", inspector, ExprType.DOUBLE);
assertOutputType("y>y_", inspector, ExprType.LONG);
assertOutputType("y_<y", inspector, ExprType.LONG);
assertOutputType("y_<=y", inspector, ExprType.LONG);
assertOutputType("y_>=y", inspector, ExprType.LONG);
assertOutputType("y_==y", inspector, ExprType.LONG);
assertOutputType("y_!=y", inspector, ExprType.LONG);
assertOutputType("y_ && y", inspector, ExprType.LONG);
assertOutputType("y_ || y", inspector, ExprType.LONG);
assertOutputType("z>y_", inspector, ExprType.DOUBLE);
assertOutputType("z<y", inspector, ExprType.DOUBLE);
assertOutputType("z<=y", inspector, ExprType.DOUBLE);
assertOutputType("y>=z", inspector, ExprType.DOUBLE);
assertOutputType("z==y", inspector, ExprType.DOUBLE);
assertOutputType("z!=y", inspector, ExprType.DOUBLE);
assertOutputType("z && y", inspector, ExprType.DOUBLE);
assertOutputType("y || z", inspector, ExprType.DOUBLE);
assertOutputType("z>z_", inspector, ExprType.DOUBLE);
assertOutputType("z<z_", inspector, ExprType.DOUBLE);
assertOutputType("z<=z_", inspector, ExprType.DOUBLE);
assertOutputType("z_>=z", inspector, ExprType.DOUBLE);
assertOutputType("z==z_", inspector, ExprType.DOUBLE);
assertOutputType("z!=z_", inspector, ExprType.DOUBLE);
assertOutputType("z && z_", inspector, ExprType.DOUBLE);
assertOutputType("z_ || z", inspector, ExprType.DOUBLE);
assertOutputType("1*(2 + 3.0)", inspector, ExprType.DOUBLE);
}
@Test
public void testUnivariateMathFunctions()
{
assertOutputType("pi()", inspector, ExprType.DOUBLE);
assertOutputType("abs(x)", inspector, ExprType.STRING);
assertOutputType("abs(y)", inspector, ExprType.LONG);
assertOutputType("abs(z)", inspector, ExprType.DOUBLE);
assertOutputType("cos(y)", inspector, ExprType.DOUBLE);
assertOutputType("cos(z)", inspector, ExprType.DOUBLE);
}
@Test
public void testBivariateMathFunctions()
{
assertOutputType("div(y,y_)", inspector, ExprType.LONG);
assertOutputType("div(y,z_)", inspector, ExprType.LONG);
assertOutputType("div(z,z_)", inspector, ExprType.LONG);
assertOutputType("max(y,y_)", inspector, ExprType.LONG);
assertOutputType("max(y,z_)", inspector, ExprType.DOUBLE);
assertOutputType("max(z,z_)", inspector, ExprType.DOUBLE);
assertOutputType("hypot(y,y_)", inspector, ExprType.DOUBLE);
assertOutputType("hypot(y,z_)", inspector, ExprType.DOUBLE);
assertOutputType("hypot(z,z_)", inspector, ExprType.DOUBLE);
}
@Test
public void testConditionalFunctions()
{
assertOutputType("if(y, 'foo', 'bar')", inspector, ExprType.STRING);
assertOutputType("if(y,2,3)", inspector, ExprType.LONG);
assertOutputType("if(y,2,3.0)", inspector, ExprType.DOUBLE);
assertOutputType(
"case_simple(x,'baz','is baz','foo','is foo','is other')",
inspector,
ExprType.STRING
);
assertOutputType(
"case_simple(y,2,2,3,3,4)",
inspector,
ExprType.LONG
);
assertOutputType(
"case_simple(z,2.0,2.0,3.0,3.0,4.0)",
inspector,
ExprType.DOUBLE
);
assertOutputType(
"case_simple(y,2,2,3,3.0,4)",
inspector,
ExprType.DOUBLE
);
assertOutputType(
"case_simple(z,2.0,2.0,3.0,3.0,null)",
inspector,
ExprType.DOUBLE
);
assertOutputType(
"case_searched(x=='baz','is baz',x=='foo','is foo','is other')",
inspector,
ExprType.STRING
);
assertOutputType(
"case_searched(y==1,1,y==2,2,0)",
inspector,
ExprType.LONG
);
assertOutputType(
"case_searched(z==1.0,1.0,z==2.0,2.0,0.0)",
inspector,
ExprType.DOUBLE
);
assertOutputType(
"case_searched(y==1,1,y==2,2.0,0)",
inspector,
ExprType.DOUBLE
);
assertOutputType(
"case_searched(z==1.0,1,z==2.0,2,null)",
inspector,
ExprType.LONG
);
assertOutputType(
"case_searched(z==1.0,1.0,z==2.0,2.0,null)",
inspector,
ExprType.DOUBLE
);
assertOutputType("nvl(x, 'foo')", inspector, ExprType.STRING);
assertOutputType("nvl(y, 1)", inspector, ExprType.LONG);
assertOutputType("nvl(y, 1.1)", inspector, ExprType.DOUBLE);
assertOutputType("nvl(z, 2.0)", inspector, ExprType.DOUBLE);
assertOutputType("nvl(y, 2.0)", inspector, ExprType.DOUBLE);
assertOutputType("isnull(x)", inspector, ExprType.LONG);
assertOutputType("isnull(y)", inspector, ExprType.LONG);
assertOutputType("isnull(z)", inspector, ExprType.LONG);
assertOutputType("notnull(x)", inspector, ExprType.LONG);
assertOutputType("notnull(y)", inspector, ExprType.LONG);
assertOutputType("notnull(z)", inspector, ExprType.LONG);
}
@Test
public void testStringFunctions()
{
assertOutputType("concat(x, 'foo')", inspector, ExprType.STRING);
assertOutputType("concat(y, 'foo')", inspector, ExprType.STRING);
assertOutputType("concat(z, 'foo')", inspector, ExprType.STRING);
assertOutputType("strlen(x)", inspector, ExprType.LONG);
assertOutputType("format('%s', x)", inspector, ExprType.STRING);
assertOutputType("format('%s', y)", inspector, ExprType.STRING);
assertOutputType("format('%s', z)", inspector, ExprType.STRING);
assertOutputType("strpos(x, x_)", inspector, ExprType.LONG);
assertOutputType("strpos(x, y)", inspector, ExprType.LONG);
assertOutputType("strpos(x, z)", inspector, ExprType.LONG);
assertOutputType("substring(x, 1, 2)", inspector, ExprType.STRING);
assertOutputType("left(x, 1)", inspector, ExprType.STRING);
assertOutputType("right(x, 1)", inspector, ExprType.STRING);
assertOutputType("replace(x, 'foo', '')", inspector, ExprType.STRING);
assertOutputType("lower(x)", inspector, ExprType.STRING);
assertOutputType("upper(x)", inspector, ExprType.STRING);
assertOutputType("reverse(x)", inspector, ExprType.STRING);
assertOutputType("repeat(x, 4)", inspector, ExprType.STRING);
}
@Test
public void testArrayFunctions()
{
assertOutputType("array(1, 2, 3)", inspector, ExprType.LONG_ARRAY);
assertOutputType("array(1, 2, 3.0)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("array_length(a)", inspector, ExprType.LONG);
assertOutputType("array_length(b)", inspector, ExprType.LONG);
assertOutputType("array_length(c)", inspector, ExprType.LONG);
assertOutputType("string_to_array(x, ',')", inspector, ExprType.STRING_ARRAY);
assertOutputType("array_to_string(a, ',')", inspector, ExprType.STRING);
assertOutputType("array_to_string(b, ',')", inspector, ExprType.STRING);
assertOutputType("array_to_string(c, ',')", inspector, ExprType.STRING);
assertOutputType("array_offset(a, 1)", inspector, ExprType.STRING);
assertOutputType("array_offset(b, 1)", inspector, ExprType.LONG);
assertOutputType("array_offset(c, 1)", inspector, ExprType.DOUBLE);
assertOutputType("array_ordinal(a, 1)", inspector, ExprType.STRING);
assertOutputType("array_ordinal(b, 1)", inspector, ExprType.LONG);
assertOutputType("array_ordinal(c, 1)", inspector, ExprType.DOUBLE);
assertOutputType("array_offset_of(a, 'a')", inspector, ExprType.LONG);
assertOutputType("array_offset_of(b, 1)", inspector, ExprType.LONG);
assertOutputType("array_offset_of(c, 1.0)", inspector, ExprType.LONG);
assertOutputType("array_ordinal_of(a, 'a')", inspector, ExprType.LONG);
assertOutputType("array_ordinal_of(b, 1)", inspector, ExprType.LONG);
assertOutputType("array_ordinal_of(c, 1.0)", inspector, ExprType.LONG);
assertOutputType("array_append(x, x_)", inspector, ExprType.STRING_ARRAY);
assertOutputType("array_append(a, x_)", inspector, ExprType.STRING_ARRAY);
assertOutputType("array_append(y, y_)", inspector, ExprType.LONG_ARRAY);
assertOutputType("array_append(b, y_)", inspector, ExprType.LONG_ARRAY);
assertOutputType("array_append(z, z_)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("array_append(c, z_)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("array_concat(x, a)", inspector, ExprType.STRING_ARRAY);
assertOutputType("array_concat(a, a)", inspector, ExprType.STRING_ARRAY);
assertOutputType("array_concat(y, b)", inspector, ExprType.LONG_ARRAY);
assertOutputType("array_concat(b, b)", inspector, ExprType.LONG_ARRAY);
assertOutputType("array_concat(z, c)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("array_concat(c, c)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("array_contains(a, 'a')", inspector, ExprType.LONG);
assertOutputType("array_contains(b, 1)", inspector, ExprType.LONG);
assertOutputType("array_contains(c, 2.0)", inspector, ExprType.LONG);
assertOutputType("array_overlap(a, a)", inspector, ExprType.LONG);
assertOutputType("array_overlap(b, b)", inspector, ExprType.LONG);
assertOutputType("array_overlap(c, c)", inspector, ExprType.LONG);
assertOutputType("array_slice(a, 1, 2)", inspector, ExprType.STRING_ARRAY);
assertOutputType("array_slice(b, 1, 2)", inspector, ExprType.LONG_ARRAY);
assertOutputType("array_slice(c, 1, 2)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("array_prepend(x, a)", inspector, ExprType.STRING_ARRAY);
assertOutputType("array_prepend(x, x_)", inspector, ExprType.STRING_ARRAY);
assertOutputType("array_prepend(y, b)", inspector, ExprType.LONG_ARRAY);
assertOutputType("array_prepend(y, y_)", inspector, ExprType.LONG_ARRAY);
assertOutputType("array_prepend(z, c)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("array_prepend(z, z_)", inspector, ExprType.DOUBLE_ARRAY);
}
@Test
public void testReduceFunctions()
{
assertOutputType("greatest('B', x, 'A')", inspector, ExprType.STRING);
assertOutputType("greatest(y, 0)", inspector, ExprType.LONG);
assertOutputType("greatest(34.0, z, 5.0, 767.0)", inspector, ExprType.DOUBLE);
assertOutputType("least('B', x, 'A')", inspector, ExprType.STRING);
assertOutputType("least(y, 0)", inspector, ExprType.LONG);
assertOutputType("least(34.0, z, 5.0, 767.0)", inspector, ExprType.DOUBLE);
}
@Test
public void testApplyFunctions()
{
assertOutputType("map((x) -> concat(x, 'foo'), x)", inspector, ExprType.STRING_ARRAY);
assertOutputType("map((x) -> x + x, y)", inspector, ExprType.LONG_ARRAY);
assertOutputType("map((x) -> x + x, z)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("map((x) -> concat(x, 'foo'), a)", inspector, ExprType.STRING_ARRAY);
assertOutputType("map((x) -> x + x, b)", inspector, ExprType.LONG_ARRAY);
assertOutputType("map((x) -> x + x, c)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType(
"cartesian_map((x, y) -> concat(x, y), ['foo', 'bar', 'baz', 'foobar'], ['bar', 'baz'])",
inspector,
ExprType.STRING_ARRAY
);
assertOutputType("fold((x, acc) -> x + acc, y, 0)", inspector, ExprType.LONG);
assertOutputType("fold((x, acc) -> x + acc, y, y)", inspector, ExprType.LONG);
assertOutputType("fold((x, acc) -> x + acc, y, 1.0)", inspector, ExprType.DOUBLE);
assertOutputType("fold((x, acc) -> x + acc, y, z)", inspector, ExprType.DOUBLE);
assertOutputType("cartesian_fold((x, y, acc) -> x + y + acc, y, z, 0)", inspector, ExprType.LONG);
assertOutputType("cartesian_fold((x, y, acc) -> x + y + acc, y, z, y)", inspector, ExprType.LONG);
assertOutputType("cartesian_fold((x, y, acc) -> x + y + acc, y, z, 1.0)", inspector, ExprType.DOUBLE);
assertOutputType("cartesian_fold((x, y, acc) -> x + y + acc, y, z, z)", inspector, ExprType.DOUBLE);
assertOutputType("filter((x) -> x == 'foo', a)", inspector, ExprType.STRING_ARRAY);
assertOutputType("filter((x) -> x > 1, b)", inspector, ExprType.LONG_ARRAY);
assertOutputType("filter((x) -> x > 1, c)", inspector, ExprType.DOUBLE_ARRAY);
assertOutputType("any((x) -> x == 'foo', a)", inspector, ExprType.LONG);
assertOutputType("any((x) -> x > 1, b)", inspector, ExprType.LONG);
assertOutputType("any((x) -> x > 1.2, c)", inspector, ExprType.LONG);
assertOutputType("all((x) -> x == 'foo', a)", inspector, ExprType.LONG);
assertOutputType("all((x) -> x > 1, b)", inspector, ExprType.LONG);
assertOutputType("all((x) -> x > 1.2, c)", inspector, ExprType.LONG);
}
@Test
public void testEvalAutoConversion()
{
final ExprEval<?> nullStringEval = ExprEval.of(null);
final ExprEval<?> stringEval = ExprEval.of("wat");
final ExprEval<?> longEval = ExprEval.of(1L);
final ExprEval<?> doubleEval = ExprEval.of(1.0);
final ExprEval<?> arrayEval = ExprEval.ofLongArray(new Long[]{1L, 2L, 3L});
// only long stays long
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.autoDetect(longEval, longEval));
// only string stays string
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.autoDetect(nullStringEval, nullStringEval));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.autoDetect(stringEval, stringEval));
// if only 1 argument is a string, preserve the other type
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.autoDetect(nullStringEval, longEval));
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.autoDetect(longEval, nullStringEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(doubleEval, nullStringEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(nullStringEval, doubleEval));
// for operators, doubles is the catch all
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(longEval, doubleEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(doubleEval, longEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(doubleEval, doubleEval));
// ... even when non-null strings are used with non-double types
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(longEval, stringEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(doubleEval, stringEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(stringEval, doubleEval));
// arrays are not a good idea to use with this method
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(arrayEval, nullStringEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(arrayEval, doubleEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(arrayEval, longEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(nullStringEval, arrayEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(doubleEval, arrayEval));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.autoDetect(longEval, arrayEval));
}
@Test
public void testOperatorAutoConversion()
{
// nulls output other
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.operator(ExprType.LONG, null));
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.operator(null, ExprType.LONG));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.operator(ExprType.DOUBLE, null));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.operator(null, ExprType.DOUBLE));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.operator(ExprType.STRING, null));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.operator(null, ExprType.STRING));
// only long stays long
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.operator(ExprType.LONG, ExprType.LONG));
// only string stays string
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.operator(ExprType.STRING, ExprType.STRING));
// for operators, doubles is the catch all
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.operator(ExprType.LONG, ExprType.DOUBLE));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.operator(ExprType.DOUBLE, ExprType.LONG));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.operator(ExprType.DOUBLE, ExprType.DOUBLE));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.operator(ExprType.DOUBLE, ExprType.STRING));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.operator(ExprType.STRING, ExprType.DOUBLE));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.operator(ExprType.STRING, ExprType.LONG));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.operator(ExprType.LONG, ExprType.STRING));
// unless it is an array, and those have to be the same
Assert.assertEquals(ExprType.LONG_ARRAY, ExprTypeConversion.operator(ExprType.LONG_ARRAY, ExprType.LONG_ARRAY));
Assert.assertEquals(
ExprType.DOUBLE_ARRAY,
ExprTypeConversion.operator(ExprType.DOUBLE_ARRAY, ExprType.DOUBLE_ARRAY)
);
Assert.assertEquals(
ExprType.STRING_ARRAY,
ExprTypeConversion.operator(ExprType.STRING_ARRAY, ExprType.STRING_ARRAY)
);
}
@Test
public void testFunctionAutoConversion()
{
// nulls output other
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.function(ExprType.LONG, null));
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.function(null, ExprType.LONG));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.function(ExprType.DOUBLE, null));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.function(null, ExprType.DOUBLE));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.function(ExprType.STRING, null));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.function(null, ExprType.STRING));
// only long stays long
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.function(ExprType.LONG, ExprType.LONG));
// any double makes all doubles
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.function(ExprType.LONG, ExprType.DOUBLE));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.function(ExprType.DOUBLE, ExprType.LONG));
Assert.assertEquals(ExprType.DOUBLE, ExprTypeConversion.function(ExprType.DOUBLE, ExprType.DOUBLE));
// any string makes become string
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.function(ExprType.LONG, ExprType.STRING));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.function(ExprType.STRING, ExprType.LONG));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.function(ExprType.DOUBLE, ExprType.STRING));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.function(ExprType.STRING, ExprType.DOUBLE));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.function(ExprType.STRING, ExprType.STRING));
// unless it is an array, and those have to be the same
Assert.assertEquals(ExprType.LONG_ARRAY, ExprTypeConversion.function(ExprType.LONG_ARRAY, ExprType.LONG_ARRAY));
Assert.assertEquals(
ExprType.DOUBLE_ARRAY,
ExprTypeConversion.function(ExprType.DOUBLE_ARRAY, ExprType.DOUBLE_ARRAY)
);
Assert.assertEquals(
ExprType.STRING_ARRAY,
ExprTypeConversion.function(ExprType.STRING_ARRAY, ExprType.STRING_ARRAY)
);
}
@Test
public void testIntegerFunctionAutoConversion()
{
// nulls output other
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.integerMathFunction(ExprType.LONG, null));
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.integerMathFunction(null, ExprType.LONG));
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.integerMathFunction(ExprType.DOUBLE, null));
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.integerMathFunction(null, ExprType.DOUBLE));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.integerMathFunction(ExprType.STRING, null));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.integerMathFunction(null, ExprType.STRING));
// all numbers are longs
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.integerMathFunction(ExprType.LONG, ExprType.LONG));
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.integerMathFunction(ExprType.LONG, ExprType.DOUBLE));
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.integerMathFunction(ExprType.DOUBLE, ExprType.LONG));
Assert.assertEquals(ExprType.LONG, ExprTypeConversion.integerMathFunction(ExprType.DOUBLE, ExprType.DOUBLE));
// any string makes become string
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.integerMathFunction(ExprType.LONG, ExprType.STRING));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.integerMathFunction(ExprType.STRING, ExprType.LONG));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.integerMathFunction(ExprType.DOUBLE, ExprType.STRING));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.integerMathFunction(ExprType.STRING, ExprType.DOUBLE));
Assert.assertEquals(ExprType.STRING, ExprTypeConversion.integerMathFunction(ExprType.STRING, ExprType.STRING));
// unless it is an array
Assert.assertEquals(ExprType.LONG_ARRAY, ExprTypeConversion.integerMathFunction(ExprType.LONG_ARRAY, ExprType.LONG_ARRAY));
Assert.assertEquals(
ExprType.DOUBLE_ARRAY,
ExprTypeConversion.integerMathFunction(ExprType.DOUBLE_ARRAY, ExprType.DOUBLE_ARRAY)
);
Assert.assertEquals(
ExprType.STRING_ARRAY,
ExprTypeConversion.integerMathFunction(ExprType.STRING_ARRAY, ExprType.STRING_ARRAY)
);
}
@Test
public void testAutoConversionArrayMismatchArrays()
{
expectedException.expect(IAE.class);
ExprTypeConversion.function(ExprType.DOUBLE_ARRAY, ExprType.LONG_ARRAY);
}
@Test
public void testAutoConversionArrayMismatchArrayScalar()
{
expectedException.expect(IAE.class);
ExprTypeConversion.function(ExprType.DOUBLE_ARRAY, ExprType.LONG);
}
@Test
public void testAutoConversionArrayMismatchScalarArray()
{
expectedException.expect(IAE.class);
ExprTypeConversion.function(ExprType.DOUBLE, ExprType.LONG_ARRAY);
}
private void assertOutputType(String expression, Expr.InputBindingInspector inspector, ExprType outputType)
{
final Expr expr = Parser.parse(expression, ExprMacroTable.nil(), false);
Assert.assertEquals(outputType, expr.getOutputType(inspector));
}
Expr.InputBindingInspector inspectorFromMap(Map<String, ExprType> types)
{
return types::get;
}
}