blob: 2f68840955fa412ebf91bcb7934958b6508bde1e [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.ImmutableList;
import com.google.common.collect.ImmutableMap;
import junitparams.converters.Nullable;
import org.apache.druid.collections.SerializablePair;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.segment.column.TypeStrategies;
import org.apache.druid.segment.column.TypeStrategiesTest;
import org.apache.druid.segment.nested.StructuredData;
import org.apache.druid.testing.InitializedNullHandlingTest;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
*/
public class EvalTest extends InitializedNullHandlingTest
{
@BeforeClass
public static void setupClass()
{
TypeStrategies.registerComplex(
TypeStrategiesTest.NULLABLE_TEST_PAIR_TYPE.getComplexTypeName(),
new TypeStrategiesTest.NullableLongPairTypeStrategy()
);
}
private long evalLong(String x, Expr.ObjectBinding bindings)
{
ExprEval ret = eval(x, bindings);
assertEquals(ExpressionType.LONG, ret.type());
return ret.asLong();
}
private double evalDouble(String x, Expr.ObjectBinding bindings)
{
ExprEval ret = eval(x, bindings);
assertEquals(ExpressionType.DOUBLE, ret.type());
return ret.asDouble();
}
private ExprEval eval(String x, Expr.ObjectBinding bindings)
{
return Parser.parse(x, ExprMacroTable.nil()).eval(bindings);
}
@Test
public void testDoubleEval()
{
Expr.ObjectBinding bindings = InputBindings.forMap(ImmutableMap.of("x", 2.0d));
assertEquals(2.0, evalDouble("x", bindings), 0.0001);
assertEquals(2.0, evalDouble("\"x\"", bindings), 0.0001);
assertEquals(304.0, evalDouble("300 + \"x\" * 2", bindings), 0.0001);
try {
ExpressionProcessing.initializeForStrictBooleansTests(false);
Assert.assertFalse(evalDouble("1.0 && 0.0", bindings) > 0.0);
Assert.assertTrue(evalDouble("1.0 && 2.0", bindings) > 0.0);
Assert.assertTrue(evalDouble("1.0 || 0.0", bindings) > 0.0);
Assert.assertFalse(evalDouble("0.0 || 0.0", bindings) > 0.0);
Assert.assertTrue(evalDouble("2.0 > 1.0", bindings) > 0.0);
Assert.assertTrue(evalDouble("2.0 >= 2.0", bindings) > 0.0);
Assert.assertTrue(evalDouble("1.0 < 2.0", bindings) > 0.0);
Assert.assertTrue(evalDouble("2.0 <= 2.0", bindings) > 0.0);
Assert.assertTrue(evalDouble("2.0 == 2.0", bindings) > 0.0);
Assert.assertTrue(evalDouble("2.0 != 1.0", bindings) > 0.0);
Assert.assertEquals(1L, evalLong("notdistinctfrom(2.0, 2.0)", bindings));
Assert.assertEquals(1L, evalLong("isdistinctfrom(2.0, 1.0)", bindings));
Assert.assertEquals(0L, evalLong("notdistinctfrom(2.0, 1.0)", bindings));
Assert.assertEquals(0L, evalLong("isdistinctfrom(2.0, 2.0)", bindings));
Assert.assertEquals(0L, evalLong("istrue(0.0)", bindings));
Assert.assertEquals(1L, evalLong("isfalse(0.0)", bindings));
Assert.assertEquals(1L, evalLong("nottrue(0.0)", bindings));
Assert.assertEquals(0L, evalLong("notfalse(0.0)", bindings));
Assert.assertEquals(1L, evalLong("istrue(1.0)", bindings));
Assert.assertEquals(0L, evalLong("isfalse(1.0)", bindings));
Assert.assertEquals(0L, evalLong("nottrue(1.0)", bindings));
Assert.assertEquals(1L, evalLong("notfalse(1.0)", bindings));
Assert.assertTrue(evalDouble("!-1.0", bindings) > 0.0);
Assert.assertTrue(evalDouble("!0.0", bindings) > 0.0);
Assert.assertFalse(evalDouble("!2.0", bindings) > 0.0);
}
finally {
ExpressionProcessing.initializeForTests();
}
try {
ExpressionProcessing.initializeForStrictBooleansTests(true);
Assert.assertEquals(0L, evalLong("1.0 && 0.0", bindings));
Assert.assertEquals(1L, evalLong("1.0 && 2.0", bindings));
Assert.assertEquals(1L, evalLong("1.0 || 0.0", bindings));
Assert.assertEquals(0L, evalLong("0.0 || 0.0", bindings));
Assert.assertEquals(1L, evalLong("2.0 > 1.0", bindings));
Assert.assertEquals(1L, evalLong("2.0 >= 2.0", bindings));
Assert.assertEquals(1L, evalLong("1.0 < 2.0", bindings));
Assert.assertEquals(1L, evalLong("2.0 <= 2.0", bindings));
Assert.assertEquals(1L, evalLong("2.0 == 2.0", bindings));
Assert.assertEquals(1L, evalLong("2.0 != 1.0", bindings));
Assert.assertEquals(1L, evalLong("notdistinctfrom(2.0, 2.0)", bindings));
Assert.assertEquals(1L, evalLong("isdistinctfrom(2.0, 1.0)", bindings));
Assert.assertEquals(0L, evalLong("notdistinctfrom(2.0, 1.0)", bindings));
Assert.assertEquals(0L, evalLong("isdistinctfrom(2.0, 2.0)", bindings));
Assert.assertEquals(0L, evalLong("istrue(0.0)", bindings));
Assert.assertEquals(1L, evalLong("isfalse(0.0)", bindings));
Assert.assertEquals(1L, evalLong("nottrue(0.0)", bindings));
Assert.assertEquals(0L, evalLong("notfalse(0.0)", bindings));
Assert.assertEquals(1L, evalLong("istrue(1.0)", bindings));
Assert.assertEquals(0L, evalLong("isfalse(1.0)", bindings));
Assert.assertEquals(0L, evalLong("nottrue(1.0)", bindings));
Assert.assertEquals(1L, evalLong("notfalse(1.0)", bindings));
Assert.assertEquals(1L, evalLong("!-1.0", bindings));
Assert.assertEquals(1L, evalLong("!0.0", bindings));
Assert.assertEquals(0L, evalLong("!2.0", bindings));
assertEquals(3.5, evalDouble("2.0 + 1.5", bindings), 0.0001);
assertEquals(0.5, evalDouble("2.0 - 1.5", bindings), 0.0001);
assertEquals(3.0, evalDouble("2.0 * 1.5", bindings), 0.0001);
assertEquals(4.0, evalDouble("2.0 / 0.5", bindings), 0.0001);
assertEquals(0.2, evalDouble("2.0 % 0.3", bindings), 0.0001);
assertEquals(8.0, evalDouble("2.0 ^ 3.0", bindings), 0.0001);
assertEquals(-1.5, evalDouble("-1.5", bindings), 0.0001);
assertEquals(2.0, evalDouble("sqrt(4.0)", bindings), 0.0001);
assertEquals(2.0, evalDouble("if(1.0, 2.0, 3.0)", bindings), 0.0001);
assertEquals(3.0, evalDouble("if(0.0, 2.0, 3.0)", bindings), 0.0001);
}
finally {
ExpressionProcessing.initializeForTests();
}
}
@Test
public void testLongEval()
{
Expr.ObjectBinding bindings = InputBindings.forMap(ImmutableMap.of("x", 9223372036854775807L));
assertEquals(9223372036854775807L, evalLong("x", bindings));
assertEquals(9223372036854775807L, evalLong("\"x\"", bindings));
assertEquals(92233720368547759L, evalLong("\"x\" / 100 + 1", bindings));
Assert.assertFalse(evalLong("9223372036854775807 && 0", bindings) > 0);
Assert.assertTrue(evalLong("9223372036854775807 && 9223372036854775806", bindings) > 0);
Assert.assertTrue(evalLong("9223372036854775807 || 0", bindings) > 0);
Assert.assertFalse(evalLong("-9223372036854775807 || -9223372036854775807", bindings) > 0);
Assert.assertTrue(evalLong("-9223372036854775807 || 9223372036854775807", bindings) > 0);
Assert.assertFalse(evalLong("0 || 0", bindings) > 0);
Assert.assertTrue(evalLong("9223372036854775807 > 9223372036854775806", bindings) > 0);
Assert.assertTrue(evalLong("9223372036854775807 >= 9223372036854775807", bindings) > 0);
Assert.assertTrue(evalLong("9223372036854775806 < 9223372036854775807", bindings) > 0);
Assert.assertTrue(evalLong("9223372036854775807 <= 9223372036854775807", bindings) > 0);
Assert.assertTrue(evalLong("9223372036854775807 == 9223372036854775807", bindings) > 0);
Assert.assertTrue(evalLong("9223372036854775807 != 9223372036854775806", bindings) > 0);
Assert.assertTrue(evalLong("notdistinctfrom(9223372036854775807, 9223372036854775807)", bindings) > 0);
Assert.assertTrue(evalLong("isdistinctfrom(9223372036854775807, 9223372036854775806)", bindings) > 0);
assertEquals(9223372036854775807L, evalLong("9223372036854775806 + 1", bindings));
assertEquals(9223372036854775806L, evalLong("9223372036854775807 - 1", bindings));
assertEquals(9223372036854775806L, evalLong("4611686018427387903 * 2", bindings));
assertEquals(4611686018427387903L, evalLong("9223372036854775806 / 2", bindings));
assertEquals(7L, evalLong("9223372036854775807 % 9223372036854775800", bindings));
assertEquals(9223372030926249001L, evalLong("3037000499 ^ 2", bindings));
assertEquals(-9223372036854775807L, evalLong("-9223372036854775807", bindings));
Assert.assertTrue(evalLong("!-9223372036854775807", bindings) > 0);
Assert.assertTrue(evalLong("!0", bindings) > 0);
Assert.assertFalse(evalLong("!9223372036854775807", bindings) > 0);
assertEquals(3037000499L, evalLong("cast(sqrt(9223372036854775807), 'long')", bindings));
assertEquals(1L, evalLong("if(x == 9223372036854775807, 1, 0)", bindings));
assertEquals(0L, evalLong("if(x - 1 == 9223372036854775807, 1, 0)", bindings));
assertEquals(1271030400000L, evalLong("timestamp('2010-04-12')", bindings));
assertEquals(1270998000000L, evalLong("timestamp('2010-04-12T+09:00')", bindings));
assertEquals(1271055781000L, evalLong("timestamp('2010-04-12T07:03:01')", bindings));
assertEquals(1271023381000L, evalLong("timestamp('2010-04-12T07:03:01+09:00')", bindings));
assertEquals(1271023381419L, evalLong("timestamp('2010-04-12T07:03:01.419+09:00')", bindings));
assertEquals(1271030400L, evalLong("unix_timestamp('2010-04-12')", bindings));
assertEquals(1270998000L, evalLong("unix_timestamp('2010-04-12T+09:00')", bindings));
assertEquals(1271055781L, evalLong("unix_timestamp('2010-04-12T07:03:01')", bindings));
assertEquals(1271023381L, evalLong("unix_timestamp('2010-04-12T07:03:01+09:00')", bindings));
assertEquals(1271023381L, evalLong("unix_timestamp('2010-04-12T07:03:01.419+09:00')", bindings));
assertEquals(
NullHandling.replaceWithDefault() ? "NULL" : "",
eval("nvl(if(x == 9223372036854775807, '', 'x'), 'NULL')", bindings).asString()
);
assertEquals("x", eval("nvl(if(x == 9223372036854775806, '', 'x'), 'NULL')", bindings).asString());
}
@Test
public void testIsNotDistinctFrom()
{
assertEquals(
1L,
new Function.IsNotDistinctFromFunc()
.apply(
ImmutableList.of(
new NullLongExpr(),
new NullLongExpr()
),
InputBindings.nilBindings()
)
.value()
);
assertEquals(
0L,
new Function.IsNotDistinctFromFunc()
.apply(
ImmutableList.of(
new LongExpr(0L),
new NullLongExpr()
),
InputBindings.nilBindings()
)
.value()
);
assertEquals(
1L,
new Function.IsNotDistinctFromFunc()
.apply(
ImmutableList.of(
new LongExpr(0L),
new LongExpr(0L)
),
InputBindings.nilBindings()
)
.value()
);
}
@Test
public void testIsDistinctFrom()
{
assertEquals(
0L,
new Function.IsDistinctFromFunc()
.apply(
ImmutableList.of(
new NullLongExpr(),
new NullLongExpr()
),
InputBindings.nilBindings()
)
.value()
);
assertEquals(
1L,
new Function.IsDistinctFromFunc()
.apply(
ImmutableList.of(
new LongExpr(0L),
new NullLongExpr()
),
InputBindings.nilBindings()
)
.value()
);
assertEquals(
0L,
new Function.IsDistinctFromFunc()
.apply(
ImmutableList.of(
new LongExpr(0L),
new LongExpr(0L)
),
InputBindings.nilBindings()
)
.value()
);
}
@Test
public void testIsFalse()
{
assertEquals(
0L,
new Function.IsFalseFunc()
.apply(ImmutableList.of(new NullLongExpr()), InputBindings.nilBindings())
.value()
);
assertEquals(
1L,
new Function.IsFalseFunc()
.apply(ImmutableList.of(new LongExpr(0L)), InputBindings.nilBindings())
.value()
);
assertEquals(
0L,
new Function.IsFalseFunc()
.apply(ImmutableList.of(new LongExpr(1L)), InputBindings.nilBindings())
.value()
);
}
@Test
public void testIsTrue()
{
assertEquals(
0L,
new Function.IsTrueFunc()
.apply(ImmutableList.of(new NullLongExpr()), InputBindings.nilBindings())
.value()
);
assertEquals(
0L,
new Function.IsTrueFunc()
.apply(ImmutableList.of(new LongExpr(0L)), InputBindings.nilBindings())
.value()
);
assertEquals(
1L,
new Function.IsTrueFunc()
.apply(ImmutableList.of(new LongExpr(1L)), InputBindings.nilBindings())
.value()
);
}
@Test
public void testIsNotFalse()
{
assertEquals(
1L,
new Function.IsNotFalseFunc()
.apply(ImmutableList.of(new NullLongExpr()), InputBindings.nilBindings())
.value()
);
assertEquals(
0L,
new Function.IsNotFalseFunc()
.apply(ImmutableList.of(new LongExpr(0L)), InputBindings.nilBindings())
.value()
);
assertEquals(
1L,
new Function.IsNotFalseFunc()
.apply(ImmutableList.of(new LongExpr(1L)), InputBindings.nilBindings())
.value()
);
}
@Test
public void testIsNotTrue()
{
assertEquals(
1L,
new Function.IsNotTrueFunc()
.apply(ImmutableList.of(new NullLongExpr()), InputBindings.nilBindings())
.value()
);
assertEquals(
1L,
new Function.IsNotTrueFunc()
.apply(ImmutableList.of(new LongExpr(0L)), InputBindings.nilBindings())
.value()
);
assertEquals(
0L,
new Function.IsNotTrueFunc()
.apply(ImmutableList.of(new LongExpr(1L)), InputBindings.nilBindings())
.value()
);
}
@Test
public void testArrayToScalar()
{
assertEquals(1L, ExprEval.ofLongArray(new Long[]{1L}).asLong());
assertEquals(1.0, ExprEval.ofLongArray(new Long[]{1L}).asDouble(), 0.0);
assertEquals(1, ExprEval.ofLongArray(new Long[]{1L}).asInt());
assertEquals(true, ExprEval.ofLongArray(new Long[]{1L}).asBoolean());
assertEquals("1", ExprEval.ofLongArray(new Long[]{1L}).asString());
assertEquals(null, ExprEval.ofLongArray(new Long[]{null}).asString());
assertEquals(0L, ExprEval.ofLongArray(new Long[]{1L, 2L}).asLong());
assertEquals(0.0, ExprEval.ofLongArray(new Long[]{1L, 2L}).asDouble(), 0.0);
assertEquals("[1, 2]", ExprEval.ofLongArray(new Long[]{1L, 2L}).asString());
assertEquals(0, ExprEval.ofLongArray(new Long[]{1L, 2L}).asInt());
assertEquals(false, ExprEval.ofLongArray(new Long[]{1L, 2L}).asBoolean());
assertEquals(1.1, ExprEval.ofDoubleArray(new Double[]{1.1}).asDouble(), 0.0);
assertEquals(1L, ExprEval.ofDoubleArray(new Double[]{1.1}).asLong());
assertEquals("1.1", ExprEval.ofDoubleArray(new Double[]{1.1}).asString());
assertEquals(1, ExprEval.ofDoubleArray(new Double[]{1.1}).asInt());
assertEquals(true, ExprEval.ofDoubleArray(new Double[]{1.1}).asBoolean());
assertEquals(null, ExprEval.ofDoubleArray(new Double[]{null}).asString());
assertEquals(0.0, ExprEval.ofDoubleArray(new Double[]{1.1, 2.2}).asDouble(), 0.0);
assertEquals(0L, ExprEval.ofDoubleArray(new Double[]{1.1, 2.2}).asLong());
assertEquals("[1.1, 2.2]", ExprEval.ofDoubleArray(new Double[]{1.1, 2.2}).asString());
assertEquals(0, ExprEval.ofDoubleArray(new Double[]{1.1, 2.2}).asInt());
assertEquals(false, ExprEval.ofDoubleArray(new Double[]{1.1, 2.2}).asBoolean());
assertEquals("foo", ExprEval.ofStringArray(new String[]{"foo"}).asString());
assertEquals("1", ExprEval.ofStringArray(new String[]{"1"}).asString());
assertEquals(1L, ExprEval.ofStringArray(new String[]{"1"}).asLong());
assertEquals(1.0, ExprEval.ofStringArray(new String[]{"1"}).asDouble(), 0.0);
assertEquals(1, ExprEval.ofStringArray(new String[]{"1"}).asInt());
assertEquals(false, ExprEval.ofStringArray(new String[]{"1"}).asBoolean());
assertEquals(true, ExprEval.ofStringArray(new String[]{"true"}).asBoolean());
assertEquals("[1, 2.2]", ExprEval.ofStringArray(new String[]{"1", "2.2"}).asString());
assertEquals(0L, ExprEval.ofStringArray(new String[]{"1", "2.2"}).asLong());
assertEquals(0.0, ExprEval.ofStringArray(new String[]{"1", "2.2"}).asDouble(), 0.0);
assertEquals(0, ExprEval.ofStringArray(new String[]{"1", "2.2"}).asInt());
assertEquals(false, ExprEval.ofStringArray(new String[]{"1", "2.2"}).asBoolean());
// test casting arrays to scalars
assertEquals(1L, ExprEval.ofLongArray(new Long[]{1L}).castTo(ExpressionType.LONG).value());
assertEquals(null, ExprEval.ofLongArray(new Long[]{null}).castTo(ExpressionType.LONG).value());
assertEquals(1.0, ExprEval.ofLongArray(new Long[]{1L}).castTo(ExpressionType.DOUBLE).asDouble(), 0.0);
assertEquals("1", ExprEval.ofLongArray(new Long[]{1L}).castTo(ExpressionType.STRING).value());
assertEquals(1.1, ExprEval.ofDoubleArray(new Double[]{1.1}).castTo(ExpressionType.DOUBLE).asDouble(), 0.0);
assertEquals(null, ExprEval.ofDoubleArray(new Double[]{null}).castTo(ExpressionType.DOUBLE).value());
assertEquals(1L, ExprEval.ofDoubleArray(new Double[]{1.1}).castTo(ExpressionType.LONG).value());
assertEquals("1.1", ExprEval.ofDoubleArray(new Double[]{1.1}).castTo(ExpressionType.STRING).value());
assertEquals("foo", ExprEval.ofStringArray(new String[]{"foo"}).castTo(ExpressionType.STRING).value());
assertEquals(null, ExprEval.ofStringArray(new String[]{"foo"}).castTo(ExpressionType.LONG).value());
assertEquals(null, ExprEval.ofStringArray(new String[]{"foo"}).castTo(ExpressionType.DOUBLE).value());
assertEquals("1", ExprEval.ofStringArray(new String[]{"1"}).castTo(ExpressionType.STRING).value());
assertEquals(1L, ExprEval.ofStringArray(new String[]{"1"}).castTo(ExpressionType.LONG).value());
assertEquals(1.0, ExprEval.ofStringArray(new String[]{"1"}).castTo(ExpressionType.DOUBLE).value());
}
@Test
public void testStringArrayToScalarStringBadCast()
{
Throwable t = Assert.assertThrows(
IAE.class,
() -> ExprEval.ofStringArray(new String[]{"foo", "bar"}).castTo(ExpressionType.STRING)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<STRING>] to [STRING]", t.getMessage());
}
@Test
public void testStringArrayToScalarLongBadCast()
{
Throwable t = Assert.assertThrows(
IAE.class,
() -> ExprEval.ofStringArray(new String[]{"foo", "bar"}).castTo(ExpressionType.LONG)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<STRING>] to [LONG]", t.getMessage());
}
@Test
public void testStringArrayToScalarDoubleBadCast()
{
Throwable t = Assert.assertThrows(
IAE.class,
() -> ExprEval.ofStringArray(new String[]{"foo", "bar"}).castTo(ExpressionType.DOUBLE)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<STRING>] to [DOUBLE]", t.getMessage());
}
@Test
public void testLongArrayToScalarStringBadCast()
{
Throwable t = Assert.assertThrows(
IAE.class,
() -> ExprEval.ofLongArray(new Long[]{1L, 2L}).castTo(ExpressionType.STRING)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<LONG>] to [STRING]", t.getMessage());
}
@Test
public void testLongArrayToScalarLongBadCast()
{
Throwable t = Assert.assertThrows(
IAE.class,
() -> ExprEval.ofLongArray(new Long[]{1L, 2L}).castTo(ExpressionType.LONG)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<LONG>] to [LONG]", t.getMessage());
}
@Test
public void testLongArrayToScalarDoubleBadCast()
{
Throwable t = Assert.assertThrows(
IAE.class,
() -> ExprEval.ofLongArray(new Long[]{1L, 2L}).castTo(ExpressionType.DOUBLE)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<LONG>] to [DOUBLE]", t.getMessage());
}
@Test
public void testDoubleArrayToScalarStringBadCast()
{
Throwable t = Assert.assertThrows(
IAE.class,
() -> ExprEval.ofDoubleArray(new Double[]{1.1, 2.2}).castTo(ExpressionType.STRING)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<DOUBLE>] to [STRING]", t.getMessage());
}
@Test
public void testDoubleArrayToScalarLongBadCast()
{
Throwable t = Assert.assertThrows(
IAE.class,
() -> ExprEval.ofDoubleArray(new Double[]{1.1, 2.2}).castTo(ExpressionType.LONG)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<DOUBLE>] to [LONG]", t.getMessage());
}
@Test
public void testDoubleArrayToScalarDoubleBadCast()
{
Throwable t = Assert.assertThrows(
IAE.class,
() -> ExprEval.ofDoubleArray(new Double[]{1.1, 2.2}).castTo(ExpressionType.DOUBLE)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<DOUBLE>] to [DOUBLE]", t.getMessage());
}
@Test
public void testNestedDataCast()
{
ExprEval cast;
cast = ExprEval.ofComplex(ExpressionType.NESTED_DATA, "hello").castTo(ExpressionType.STRING);
Assert.assertEquals("hello", cast.value());
Assert.assertEquals("hello", ExprEval.ofComplex(ExpressionType.NESTED_DATA, "hello").asString());
Assert.assertEquals(ExpressionType.STRING, cast.type());
cast = ExprEval.of("hello").castTo(ExpressionType.NESTED_DATA);
Assert.assertEquals("hello", cast.value());
Assert.assertEquals(ExpressionType.NESTED_DATA, cast.type());
cast = ExprEval.ofComplex(ExpressionType.NESTED_DATA, 123L).castTo(ExpressionType.STRING);
Assert.assertEquals("123", cast.value());
Assert.assertEquals(ExpressionType.STRING, cast.type());
cast = ExprEval.ofComplex(ExpressionType.NESTED_DATA, 123L).castTo(ExpressionType.LONG);
Assert.assertEquals(123L, cast.value());
Assert.assertEquals(123L, ExprEval.ofComplex(ExpressionType.NESTED_DATA, 123L).asLong());
Assert.assertEquals(ExpressionType.LONG, cast.type());
cast = ExprEval.of(123L).castTo(ExpressionType.NESTED_DATA);
Assert.assertEquals(123L, cast.value());
Assert.assertEquals(ExpressionType.NESTED_DATA, cast.type());
cast = ExprEval.ofComplex(ExpressionType.NESTED_DATA, 123L).castTo(ExpressionType.DOUBLE);
Assert.assertEquals(123.0, cast.value());
Assert.assertEquals(123.0, ExprEval.ofComplex(ExpressionType.NESTED_DATA, 123L).asDouble(), 0.0);
Assert.assertEquals(ExpressionType.DOUBLE, cast.type());
cast = ExprEval.of(12.3).castTo(ExpressionType.NESTED_DATA);
Assert.assertEquals(12.3, cast.value());
Assert.assertEquals(ExpressionType.NESTED_DATA, cast.type());
cast = ExprEval.ofComplex(ExpressionType.NESTED_DATA, ImmutableList.of("a", "b", "c")).castTo(ExpressionType.STRING_ARRAY);
Assert.assertArrayEquals(new Object[]{"a", "b", "c"}, (Object[]) cast.value());
Assert.assertArrayEquals(
new Object[]{"a", "b", "c"},
ExprEval.ofComplex(ExpressionType.NESTED_DATA, ImmutableList.of("a", "b", "c")).asArray()
);
Assert.assertEquals(ExpressionType.STRING_ARRAY, cast.type());
cast = ExprEval.ofArray(ExpressionType.STRING_ARRAY, new Object[]{"a", "b", "c"}).castTo(ExpressionType.NESTED_DATA);
Assert.assertArrayEquals(new Object[]{"a", "b", "c"}, (Object[]) cast.value());
Assert.assertEquals(ExpressionType.NESTED_DATA, cast.type());
cast = ExprEval.ofComplex(ExpressionType.NESTED_DATA, ImmutableList.of(1L, 2L, 3L)).castTo(ExpressionType.LONG_ARRAY);
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) cast.value());
Assert.assertArrayEquals(
new Object[]{1L, 2L, 3L},
ExprEval.ofComplex(ExpressionType.NESTED_DATA, ImmutableList.of(1L, 2L, 3L)).asArray()
);
Assert.assertEquals(ExpressionType.LONG_ARRAY, cast.type());
cast = ExprEval.ofArray(ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L}).castTo(ExpressionType.NESTED_DATA);
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) cast.value());
Assert.assertEquals(ExpressionType.NESTED_DATA, cast.type());
cast = ExprEval.ofComplex(ExpressionType.NESTED_DATA, ImmutableList.of(1L, 2L, 3L)).castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) cast.value());
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, cast.type());
cast = ExprEval.ofArray(ExpressionType.DOUBLE_ARRAY, new Object[]{1.1, 2.2, 3.3}).castTo(ExpressionType.NESTED_DATA);
Assert.assertArrayEquals(new Object[]{1.1, 2.2, 3.3}, (Object[]) cast.value());
Assert.assertEquals(ExpressionType.NESTED_DATA, cast.type());
ExpressionType nestedArray = ExpressionTypeFactory.getInstance().ofArray(ExpressionType.NESTED_DATA);
cast = ExprEval.ofComplex(
ExpressionType.NESTED_DATA,
ImmutableList.of(ImmutableMap.of("x", 1, "y", 2), ImmutableMap.of("x", 3, "y", 4))
).castTo(nestedArray);
Assert.assertArrayEquals(
new Object[]{
ImmutableMap.of("x", 1, "y", 2),
ImmutableMap.of("x", 3, "y", 4)
},
(Object[]) cast.value()
);
Assert.assertEquals(nestedArray, cast.type());
Assert.assertArrayEquals(
new Object[]{
ImmutableMap.of("x", 1, "y", 2),
ImmutableMap.of("x", 3, "y", 4)
},
ExprEval.ofComplex(
ExpressionType.NESTED_DATA,
ImmutableList.of(
ImmutableMap.of("x", 1, "y", 2),
ImmutableMap.of("x", 3, "y", 4)
)
).asArray()
);
cast = ExprEval.ofLong(1234L).castTo(nestedArray);
Assert.assertEquals(nestedArray, cast.type());
Assert.assertArrayEquals(
new Object[]{1234L},
cast.asArray()
);
cast = ExprEval.of("hello").castTo(nestedArray);
Assert.assertEquals(nestedArray, cast.type());
Assert.assertArrayEquals(
new Object[]{"hello"},
cast.asArray()
);
cast = ExprEval.ofDouble(1.234).castTo(nestedArray);
Assert.assertEquals(nestedArray, cast.type());
Assert.assertArrayEquals(
new Object[]{1.234},
cast.asArray()
);
cast = ExprEval.ofComplex(ExpressionType.NESTED_DATA, 1234L).castTo(nestedArray);
Assert.assertArrayEquals(
new Object[]{1234L},
cast.asArray()
);
Assert.assertEquals(nestedArray, cast.type());
}
@Test
public void testNestedAsOtherStuff()
{
ExprEval eval = ExprEval.ofComplex(ExpressionType.NESTED_DATA, StructuredData.wrap(true));
Assert.assertTrue(eval.asBoolean());
Assert.assertFalse(eval.isNumericNull());
Assert.assertEquals(1, eval.asInt());
Assert.assertEquals(1L, eval.asLong());
Assert.assertEquals(1.0, eval.asDouble(), 0.0);
Assert.assertTrue(ExprEval.ofComplex(ExpressionType.NESTED_DATA, true).asBoolean());
eval = ExprEval.ofComplex(ExpressionType.NESTED_DATA, false);
Assert.assertFalse(eval.asBoolean());
Assert.assertFalse(eval.isNumericNull());
Assert.assertEquals(0, eval.asInt());
Assert.assertEquals(0L, eval.asLong());
Assert.assertEquals(0.0, eval.asDouble(), 0.0);
eval = ExprEval.ofComplex(ExpressionType.NESTED_DATA, "true");
Assert.assertTrue(eval.asBoolean());
Assert.assertFalse(eval.isNumericNull());
Assert.assertEquals(1L, eval.asLong());
Assert.assertEquals(1, eval.asInt());
Assert.assertEquals(1.0, eval.asDouble(), 0.0);
Assert.assertTrue(ExprEval.ofComplex(ExpressionType.NESTED_DATA, StructuredData.wrap("true")).asBoolean());
Assert.assertTrue(ExprEval.ofComplex(ExpressionType.NESTED_DATA, "TRUE").asBoolean());
Assert.assertTrue(ExprEval.ofComplex(ExpressionType.NESTED_DATA, "True").asBoolean());
eval = ExprEval.ofComplex(ExpressionType.NESTED_DATA, StructuredData.wrap(1L));
Assert.assertTrue(eval.asBoolean());
Assert.assertFalse(eval.isNumericNull());
Assert.assertEquals(1L, eval.asLong());
Assert.assertEquals(1, eval.asInt());
Assert.assertEquals(1.0, eval.asDouble(), 0.0);
Assert.assertTrue(ExprEval.ofComplex(ExpressionType.NESTED_DATA, 1L).asBoolean());
eval = ExprEval.ofComplex(ExpressionType.NESTED_DATA, StructuredData.wrap(1.23));
Assert.assertTrue(eval.asBoolean());
Assert.assertFalse(eval.isNumericNull());
Assert.assertEquals(1L, eval.asLong());
Assert.assertEquals(1, eval.asInt());
Assert.assertEquals(1.23, eval.asDouble(), 0.0);
eval = ExprEval.ofComplex(ExpressionType.NESTED_DATA, "hello");
Assert.assertFalse(eval.asBoolean());
Assert.assertTrue(eval.isNumericNull());
Assert.assertEquals(0, eval.asInt());
Assert.assertEquals(0L, eval.asLong());
Assert.assertEquals(0.0, eval.asDouble(), 0.0);
eval = ExprEval.ofComplex(ExpressionType.NESTED_DATA, Arrays.asList("1", "2", "3"));
Assert.assertFalse(eval.asBoolean());
Assert.assertTrue(eval.isNumericNull());
Assert.assertEquals(0, eval.asInt());
Assert.assertEquals(0L, eval.asLong());
Assert.assertEquals(0.0, eval.asDouble(), 0.0);
Assert.assertArrayEquals(new Object[]{"1", "2", "3"}, eval.asArray());
eval = ExprEval.ofComplex(ExpressionType.NESTED_DATA, Arrays.asList(1L, 2L, 3L));
Assert.assertFalse(eval.asBoolean());
Assert.assertTrue(eval.isNumericNull());
Assert.assertEquals(0, eval.asInt());
Assert.assertEquals(0L, eval.asLong());
Assert.assertEquals(0.0, eval.asDouble(), 0.0);
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, eval.asArray());
eval = ExprEval.ofComplex(ExpressionType.NESTED_DATA, Arrays.asList(1.1, 2.2, 3.3));
Assert.assertFalse(eval.asBoolean());
Assert.assertTrue(eval.isNumericNull());
Assert.assertEquals(0, eval.asInt());
Assert.assertEquals(0L, eval.asLong());
Assert.assertEquals(0.0, eval.asDouble(), 0.0);
Assert.assertArrayEquals(new Object[]{1.1, 2.2, 3.3}, eval.asArray());
eval = ExprEval.ofComplex(
ExpressionType.NESTED_DATA,
ImmutableList.of(
ImmutableMap.of("x", 1, "y", 2),
ImmutableMap.of("x", 3, "y", 4)
)
);
Assert.assertFalse(eval.asBoolean());
Assert.assertEquals(0, eval.asLong());
Assert.assertEquals(0, eval.asInt());
Assert.assertEquals(0.0, eval.asDouble(), 0.0);
}
@Test
public void testNonNestedComplexCastThrows()
{
ExpressionType someComplex = ExpressionTypeFactory.getInstance().ofComplex("tester");
Throwable t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofType(someComplex, "hello").castTo(ExpressionType.STRING)
);
Assert.assertEquals("Invalid type, cannot cast [COMPLEX<tester>] to [STRING]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofType(someComplex, "hello").castTo(ExpressionType.LONG)
);
Assert.assertEquals("Invalid type, cannot cast [COMPLEX<tester>] to [LONG]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofType(someComplex, "hello").castTo(ExpressionType.DOUBLE)
);
Assert.assertEquals("Invalid type, cannot cast [COMPLEX<tester>] to [DOUBLE]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofType(someComplex, "hello").castTo(ExpressionType.STRING_ARRAY)
);
Assert.assertEquals("Invalid type, cannot cast [COMPLEX<tester>] to [ARRAY<STRING>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofType(someComplex, "hello").castTo(ExpressionType.LONG_ARRAY)
);
Assert.assertEquals("Invalid type, cannot cast [COMPLEX<tester>] to [ARRAY<LONG>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofType(someComplex, "hello").castTo(ExpressionType.DOUBLE_ARRAY)
);
Assert.assertEquals("Invalid type, cannot cast [COMPLEX<tester>] to [ARRAY<DOUBLE>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofType(someComplex, "hello").castTo(ExpressionType.NESTED_DATA)
);
Assert.assertEquals("Invalid type, cannot cast [COMPLEX<tester>] to [COMPLEX<json>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.of("hello").castTo(someComplex)
);
Assert.assertEquals("Invalid type, cannot cast [STRING] to [COMPLEX<tester>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.of(123L).castTo(someComplex)
);
Assert.assertEquals("Invalid type, cannot cast [LONG] to [COMPLEX<tester>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.of(1.23).castTo(someComplex)
);
Assert.assertEquals("Invalid type, cannot cast [DOUBLE] to [COMPLEX<tester>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofStringArray(new Object[]{"a", "b", "c"}).castTo(someComplex)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<STRING>] to [COMPLEX<tester>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofLongArray(new Object[]{1L, 2L, 3L}).castTo(someComplex)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<LONG>] to [COMPLEX<tester>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofDoubleArray(new Object[]{1.1, 2.2, 3.3}).castTo(someComplex)
);
Assert.assertEquals("Invalid type, cannot cast [ARRAY<DOUBLE>] to [COMPLEX<tester>]", t.getMessage());
t = Assert.assertThrows(
IllegalArgumentException.class,
() -> ExprEval.ofComplex(ExpressionType.NESTED_DATA, ImmutableMap.of("x", 1L)).castTo(someComplex)
);
Assert.assertEquals("Invalid type, cannot cast [COMPLEX<json>] to [COMPLEX<tester>]", t.getMessage());
}
@Test
public void testIsNumericNull()
{
if (NullHandling.sqlCompatible()) {
Assert.assertFalse(ExprEval.ofLong(1L).isNumericNull());
Assert.assertTrue(ExprEval.ofLong(null).isNumericNull());
Assert.assertFalse(ExprEval.ofDouble(1.0).isNumericNull());
Assert.assertTrue(ExprEval.ofDouble(null).isNumericNull());
Assert.assertTrue(ExprEval.of(null).isNumericNull());
Assert.assertTrue(ExprEval.of("one").isNumericNull());
Assert.assertFalse(ExprEval.of("1").isNumericNull());
Assert.assertFalse(ExprEval.ofLongArray(new Long[]{1L}).isNumericNull());
Assert.assertTrue(ExprEval.ofLongArray(new Long[]{null, 2L, 3L}).isNumericNull());
Assert.assertTrue(ExprEval.ofLongArray(new Long[]{null}).isNumericNull());
Assert.assertFalse(ExprEval.ofDoubleArray(new Double[]{1.1}).isNumericNull());
Assert.assertTrue(ExprEval.ofDoubleArray(new Double[]{null, 1.1, 2.2}).isNumericNull());
Assert.assertTrue(ExprEval.ofDoubleArray(new Double[]{null}).isNumericNull());
Assert.assertFalse(ExprEval.ofStringArray(new String[]{"1"}).isNumericNull());
Assert.assertTrue(ExprEval.ofStringArray(new String[]{null, "1", "2"}).isNumericNull());
Assert.assertTrue(ExprEval.ofStringArray(new String[]{"one"}).isNumericNull());
Assert.assertTrue(ExprEval.ofStringArray(new String[]{null}).isNumericNull());
} else {
Assert.assertFalse(ExprEval.ofLong(1L).isNumericNull());
Assert.assertFalse(ExprEval.ofLong(null).isNumericNull());
Assert.assertFalse(ExprEval.ofDouble(1.0).isNumericNull());
Assert.assertFalse(ExprEval.ofDouble(null).isNumericNull());
// strings are still null
Assert.assertTrue(ExprEval.of(null).isNumericNull());
Assert.assertTrue(ExprEval.of("one").isNumericNull());
Assert.assertFalse(ExprEval.of("1").isNumericNull());
// arrays can still have nulls
Assert.assertFalse(ExprEval.ofLongArray(new Long[]{1L}).isNumericNull());
Assert.assertTrue(ExprEval.ofLongArray(new Long[]{null, 2L, 3L}).isNumericNull());
Assert.assertTrue(ExprEval.ofLongArray(new Long[]{null}).isNumericNull());
Assert.assertFalse(ExprEval.ofDoubleArray(new Double[]{1.1}).isNumericNull());
Assert.assertTrue(ExprEval.ofDoubleArray(new Double[]{null, 1.1, 2.2}).isNumericNull());
Assert.assertTrue(ExprEval.ofDoubleArray(new Double[]{null}).isNumericNull());
Assert.assertFalse(ExprEval.ofStringArray(new String[]{"1"}).isNumericNull());
Assert.assertTrue(ExprEval.ofStringArray(new String[]{null, "1", "2"}).isNumericNull());
Assert.assertTrue(ExprEval.ofStringArray(new String[]{"one"}).isNumericNull());
Assert.assertTrue(ExprEval.ofStringArray(new String[]{null}).isNumericNull());
}
}
@Test
public void testBooleanReturn()
{
Expr.ObjectBinding bindings = InputBindings.forMap(
ImmutableMap.of("x", 100L, "y", 100L, "z", 100D, "w", 100D)
);
try {
ExpressionProcessing.initializeForStrictBooleansTests(false);
ExprEval eval = Parser.parse("x==z", ExprMacroTable.nil()).eval(bindings);
Assert.assertTrue(eval.asBoolean());
assertEquals(ExpressionType.DOUBLE, eval.type());
eval = Parser.parse("x!=z", ExprMacroTable.nil()).eval(bindings);
Assert.assertFalse(eval.asBoolean());
assertEquals(ExpressionType.DOUBLE, eval.type());
eval = Parser.parse("z==w", ExprMacroTable.nil()).eval(bindings);
Assert.assertTrue(eval.asBoolean());
assertEquals(ExpressionType.DOUBLE, eval.type());
eval = Parser.parse("z!=w", ExprMacroTable.nil()).eval(bindings);
Assert.assertFalse(eval.asBoolean());
assertEquals(ExpressionType.DOUBLE, eval.type());
}
finally {
ExpressionProcessing.initializeForTests();
}
try {
ExpressionProcessing.initializeForStrictBooleansTests(true);
ExprEval eval = Parser.parse("x==y", ExprMacroTable.nil()).eval(bindings);
Assert.assertTrue(eval.asBoolean());
assertEquals(ExpressionType.LONG, eval.type());
eval = Parser.parse("x!=y", ExprMacroTable.nil()).eval(bindings);
Assert.assertFalse(eval.asBoolean());
assertEquals(ExpressionType.LONG, eval.type());
eval = Parser.parse("x==z", ExprMacroTable.nil()).eval(bindings);
Assert.assertTrue(eval.asBoolean());
assertEquals(ExpressionType.LONG, eval.type());
eval = Parser.parse("x!=z", ExprMacroTable.nil()).eval(bindings);
Assert.assertFalse(eval.asBoolean());
assertEquals(ExpressionType.LONG, eval.type());
eval = Parser.parse("z==w", ExprMacroTable.nil()).eval(bindings);
Assert.assertTrue(eval.asBoolean());
assertEquals(ExpressionType.LONG, eval.type());
eval = Parser.parse("z!=w", ExprMacroTable.nil()).eval(bindings);
Assert.assertFalse(eval.asBoolean());
assertEquals(ExpressionType.LONG, eval.type());
}
finally {
ExpressionProcessing.initializeForTests();
}
}
@Test
public void testLogicalOperators()
{
Expr.ObjectBinding bindings = InputBindings.nilBindings();
try {
ExpressionProcessing.initializeForStrictBooleansTests(true);
assertEquals(1L, eval("'true' && 'true'", bindings).value());
assertEquals(0L, eval("'true' && 'false'", bindings).value());
assertEquals(0L, eval("'false' && 'true'", bindings).value());
assertEquals(0L, eval("'troo' && 'true'", bindings).value());
assertEquals(0L, eval("'false' && 'false'", bindings).value());
assertEquals(1L, eval("'true' || 'true'", bindings).value());
assertEquals(1L, eval("'true' || 'false'", bindings).value());
assertEquals(1L, eval("'false' || 'true'", bindings).value());
assertEquals(1L, eval("'troo' || 'true'", bindings).value());
assertEquals(0L, eval("'false' || 'false'", bindings).value());
assertEquals(1L, eval("1 && 1", bindings).value());
assertEquals(1L, eval("100 && 11", bindings).value());
assertEquals(0L, eval("1 && 0", bindings).value());
assertEquals(0L, eval("0 && 1", bindings).value());
assertEquals(0L, eval("0 && 0", bindings).value());
assertEquals(1L, eval("1 || 1", bindings).value());
assertEquals(1L, eval("100 || 11", bindings).value());
assertEquals(1L, eval("1 || 0", bindings).value());
assertEquals(1L, eval("0 || 1", bindings).value());
assertEquals(1L, eval("111 || 0", bindings).value());
assertEquals(1L, eval("0 || 111", bindings).value());
assertEquals(0L, eval("0 || 0", bindings).value());
assertEquals(1L, eval("1.0 && 1.0", bindings).value());
assertEquals(1L, eval("0.100 && 1.1", bindings).value());
assertEquals(0L, eval("1.0 && 0.0", bindings).value());
assertEquals(0L, eval("0.0 && 1.0", bindings).value());
assertEquals(0L, eval("0.0 && 0.0", bindings).value());
assertEquals(1L, eval("1.0 || 1.0", bindings).value());
assertEquals(1L, eval("0.2 || 0.3", bindings).value());
assertEquals(1L, eval("1.0 || 0.0", bindings).value());
assertEquals(1L, eval("0.0 || 1.0", bindings).value());
assertEquals(1L, eval("1.11 || 0.0", bindings).value());
assertEquals(1L, eval("0.0 || 0.111", bindings).value());
assertEquals(0L, eval("0.0 || 0.0", bindings).value());
assertEquals(1L, eval("null || 1", bindings).value());
assertEquals(1L, eval("1 || null", bindings).value());
// in sql incompatible mode, null is false, so we return 0
assertEquals(NullHandling.defaultLongValue(), eval("null || 0", bindings).valueOrDefault());
assertEquals(NullHandling.defaultLongValue(), eval("0 || null", bindings).valueOrDefault());
assertEquals(NullHandling.defaultLongValue(), eval("null || null", bindings).valueOrDefault());
// in sql incompatible mode, null is false, so we return 0
assertEquals(NullHandling.defaultLongValue(), eval("null && 1", bindings).valueOrDefault());
assertEquals(NullHandling.defaultLongValue(), eval("1 && null", bindings).valueOrDefault());
assertEquals(NullHandling.defaultLongValue(), eval("null && null", bindings).valueOrDefault());
// if either side is false, output is false in both modes
assertEquals(0L, eval("null && 0", bindings).value());
assertEquals(0L, eval("0 && null", bindings).value());
}
finally {
// reset
ExpressionProcessing.initializeForTests();
}
try {
// turn on legacy insanity mode
ExpressionProcessing.initializeForStrictBooleansTests(false);
assertEquals("true", eval("'true' && 'true'", bindings).value());
assertEquals("false", eval("'true' && 'false'", bindings).value());
assertEquals("false", eval("'false' && 'true'", bindings).value());
assertEquals("troo", eval("'troo' && 'true'", bindings).value());
assertEquals("false", eval("'false' && 'false'", bindings).value());
assertEquals("true", eval("'true' || 'true'", bindings).value());
assertEquals("true", eval("'true' || 'false'", bindings).value());
assertEquals("true", eval("'false' || 'true'", bindings).value());
assertEquals("true", eval("'troo' || 'true'", bindings).value());
assertEquals("false", eval("'false' || 'false'", bindings).value());
assertEquals(1.0, eval("1.0 && 1.0", bindings).value());
assertEquals(1.1, eval("0.100 && 1.1", bindings).value());
assertEquals(0.0, eval("1.0 && 0.0", bindings).value());
assertEquals(0.0, eval("0.0 && 1.0", bindings).value());
assertEquals(0.0, eval("0.0 && 0.0", bindings).value());
assertEquals(1.0, eval("1.0 || 1.0", bindings).value());
assertEquals(0.2, eval("0.2 || 0.3", bindings).value());
assertEquals(1.0, eval("1.0 || 0.0", bindings).value());
assertEquals(1.0, eval("0.0 || 1.0", bindings).value());
assertEquals(1.11, eval("1.11 || 0.0", bindings).value());
assertEquals(0.111, eval("0.0 || 0.111", bindings).value());
assertEquals(0.0, eval("0.0 || 0.0", bindings).value());
assertEquals(1L, eval("1 && 1", bindings).value());
assertEquals(11L, eval("100 && 11", bindings).value());
assertEquals(0L, eval("1 && 0", bindings).value());
assertEquals(0L, eval("0 && 1", bindings).value());
assertEquals(0L, eval("0 && 0", bindings).value());
assertEquals(1L, eval("1 || 1", bindings).value());
assertEquals(100L, eval("100 || 11", bindings).value());
assertEquals(1L, eval("1 || 0", bindings).value());
assertEquals(1L, eval("0 || 1", bindings).value());
assertEquals(111L, eval("111 || 0", bindings).value());
assertEquals(111L, eval("0 || 111", bindings).value());
assertEquals(0L, eval("0 || 0", bindings).value());
assertEquals(1.0, eval("1.0 && 1.0", bindings).value());
assertEquals(1.1, eval("0.100 && 1.1", bindings).value());
assertEquals(0.0, eval("1.0 && 0.0", bindings).value());
assertEquals(0.0, eval("0.0 && 1.0", bindings).value());
assertEquals(0.0, eval("0.0 && 0.0", bindings).value());
assertEquals(1.0, eval("1.0 || 1.0", bindings).value());
assertEquals(0.2, eval("0.2 || 0.3", bindings).value());
assertEquals(1.0, eval("1.0 || 0.0", bindings).value());
assertEquals(1.0, eval("0.0 || 1.0", bindings).value());
assertEquals(1.11, eval("1.11 || 0.0", bindings).value());
assertEquals(0.111, eval("0.0 || 0.111", bindings).value());
assertEquals(0.0, eval("0.0 || 0.0", bindings).value());
assertEquals(1L, eval("null || 1", bindings).value());
assertEquals(1L, eval("1 || null", bindings).value());
assertEquals(0L, eval("null || 0", bindings).value());
Assert.assertNull(eval("0 || null", bindings).value());
Assert.assertNull(eval("null || null", bindings).value());
Assert.assertNull(eval("null && 1", bindings).value());
Assert.assertNull(eval("1 && null", bindings).value());
Assert.assertNull(eval("null && 0", bindings).value());
assertEquals(0L, eval("0 && null", bindings).value());
assertNull(eval("null && null", bindings).value());
}
finally {
// reset
ExpressionProcessing.initializeForTests();
}
}
@Test
public void testBooleanInputs()
{
Map<String, Object> bindingsMap = new HashMap<>();
bindingsMap.put("l1", 100L);
bindingsMap.put("l2", 0L);
bindingsMap.put("d1", 1.1);
bindingsMap.put("d2", 0.0);
bindingsMap.put("s1", "true");
bindingsMap.put("s2", "false");
bindingsMap.put("b1", true);
bindingsMap.put("b2", false);
Expr.ObjectBinding bindings = InputBindings.forMap(bindingsMap);
try {
ExpressionProcessing.initializeForStrictBooleansTests(true);
assertEquals(1L, eval("s1 && s1", bindings).value());
assertEquals(0L, eval("s1 && s2", bindings).value());
assertEquals(0L, eval("s2 && s1", bindings).value());
assertEquals(0L, eval("s2 && s2", bindings).value());
assertEquals(1L, eval("s1 || s1", bindings).value());
assertEquals(1L, eval("s1 || s2", bindings).value());
assertEquals(1L, eval("s2 || s1", bindings).value());
assertEquals(0L, eval("s2 || s2", bindings).value());
assertEquals(1L, eval("l1 && l1", bindings).value());
assertEquals(0L, eval("l1 && l2", bindings).value());
assertEquals(0L, eval("l2 && l1", bindings).value());
assertEquals(0L, eval("l2 && l2", bindings).value());
assertEquals(1L, eval("b1 && b1", bindings).value());
assertEquals(0L, eval("b1 && b2", bindings).value());
assertEquals(0L, eval("b2 && b1", bindings).value());
assertEquals(0L, eval("b2 && b2", bindings).value());
assertEquals(1L, eval("d1 && d1", bindings).value());
assertEquals(0L, eval("d1 && d2", bindings).value());
assertEquals(0L, eval("d2 && d1", bindings).value());
assertEquals(0L, eval("d2 && d2", bindings).value());
assertEquals(1L, eval("b1", bindings).value());
assertEquals(1L, eval("if(b1,1,0)", bindings).value());
assertEquals(1L, eval("if(l1,1,0)", bindings).value());
assertEquals(1L, eval("if(d1,1,0)", bindings).value());
assertEquals(1L, eval("if(s1,1,0)", bindings).value());
assertEquals(0L, eval("if(b2,1,0)", bindings).value());
assertEquals(0L, eval("if(l2,1,0)", bindings).value());
assertEquals(0L, eval("if(d2,1,0)", bindings).value());
assertEquals(0L, eval("if(s2,1,0)", bindings).value());
}
finally {
// reset
ExpressionProcessing.initializeForTests();
}
try {
// turn on legacy insanity mode
ExpressionProcessing.initializeForStrictBooleansTests(false);
assertEquals("true", eval("s1 && s1", bindings).value());
assertEquals("false", eval("s1 && s2", bindings).value());
assertEquals("false", eval("s2 && s1", bindings).value());
assertEquals("false", eval("s2 && s2", bindings).value());
assertEquals("true", eval("b1 && b1", bindings).value());
assertEquals("false", eval("b1 && b2", bindings).value());
assertEquals("false", eval("b2 && b1", bindings).value());
assertEquals("false", eval("b2 && b2", bindings).value());
assertEquals(100L, eval("l1 && l1", bindings).value());
assertEquals(0L, eval("l1 && l2", bindings).value());
assertEquals(0L, eval("l2 && l1", bindings).value());
assertEquals(0L, eval("l2 && l2", bindings).value());
assertEquals(1.1, eval("d1 && d1", bindings).value());
assertEquals(0.0, eval("d1 && d2", bindings).value());
assertEquals(0.0, eval("d2 && d1", bindings).value());
assertEquals(0.0, eval("d2 && d2", bindings).value());
assertEquals("true", eval("b1", bindings).value());
assertEquals(1L, eval("if(b1,1,0)", bindings).value());
assertEquals(1L, eval("if(l1,1,0)", bindings).value());
assertEquals(1L, eval("if(d1,1,0)", bindings).value());
assertEquals(1L, eval("if(s1,1,0)", bindings).value());
assertEquals(0L, eval("if(b2,1,0)", bindings).value());
assertEquals(0L, eval("if(l2,1,0)", bindings).value());
assertEquals(0L, eval("if(d2,1,0)", bindings).value());
assertEquals(0L, eval("if(s2,1,0)", bindings).value());
}
finally {
// reset
ExpressionProcessing.initializeForTests();
}
}
@Test
public void testArrayComparison()
{
Expr.ObjectBinding bindings = InputBindings.forInputSuppliers(
ImmutableMap.<String, InputBindings.InputSupplier<?>>builder()
.put(
"stringArray",
InputBindings.inputSupplier(ExpressionType.STRING_ARRAY, () -> new Object[]{"a", "b", null, "c"})
)
.put(
"longArray",
InputBindings.inputSupplier(ExpressionType.LONG_ARRAY, () -> new Object[]{1L, null, 2L, 3L})
)
.put(
"doubleArray",
InputBindings.inputSupplier(ExpressionType.DOUBLE_ARRAY, () -> new Object[]{1.1, 2.2, 3.3, null})
)
.build()
);
Assert.assertEquals(0L, eval("['a','b',null,'c'] > stringArray", bindings).value());
Assert.assertEquals(1L, eval("['a','b',null,'c'] >= stringArray", bindings).value());
Assert.assertEquals(1L, eval("['a','b',null,'c'] == stringArray", bindings).value());
Assert.assertEquals(0L, eval("['a','b',null,'c'] != stringArray", bindings).value());
Assert.assertEquals(1L, eval("notdistinctfrom(['a','b',null,'c'], stringArray)", bindings).value());
Assert.assertEquals(0L, eval("isdistinctfrom(['a','b',null,'c'], stringArray)", bindings).value());
Assert.assertEquals(1L, eval("['a','b',null,'c'] <= stringArray", bindings).value());
Assert.assertEquals(0L, eval("['a','b',null,'c'] < stringArray", bindings).value());
Assert.assertEquals(0L, eval("[1,null,2,3] > longArray", bindings).value());
Assert.assertEquals(1L, eval("[1,null,2,3] >= longArray", bindings).value());
Assert.assertEquals(1L, eval("[1,null,2,3] == longArray", bindings).value());
Assert.assertEquals(0L, eval("[1,null,2,3] != longArray", bindings).value());
Assert.assertEquals(1L, eval("notdistinctfrom([1,null,2,3], longArray)", bindings).value());
Assert.assertEquals(0L, eval("isdistinctfrom([1,null,2,3], longArray)", bindings).value());
Assert.assertEquals(1L, eval("[1,null,2,3] <= longArray", bindings).value());
Assert.assertEquals(0L, eval("[1,null,2,3] < longArray", bindings).value());
Assert.assertEquals(0L, eval("[1.1,2.2,3.3,null] > doubleArray", bindings).value());
Assert.assertEquals(1L, eval("[1.1,2.2,3.3,null] >= doubleArray", bindings).value());
Assert.assertEquals(1L, eval("[1.1,2.2,3.3,null] == doubleArray", bindings).value());
Assert.assertEquals(0L, eval("[1.1,2.2,3.3,null] != doubleArray", bindings).value());
Assert.assertEquals(1L, eval("notdistinctfrom([1.1,2.2,3.3,null], doubleArray)", bindings).value());
Assert.assertEquals(0L, eval("isdistinctfrom([1.1,2.2,3.3,null], doubleArray)", bindings).value());
Assert.assertEquals(1L, eval("[1.1,2.2,3.3,null] <= doubleArray", bindings).value());
Assert.assertEquals(0L, eval("[1.1,2.2,3.3,null] < doubleArray", bindings).value());
}
@Test
public void testValueOrDefault()
{
ExprEval<?> longNull = ExprEval.ofLong(null);
ExprEval<?> doubleNull = ExprEval.ofDouble(null);
Assert.assertEquals(NullHandling.sqlCompatible(), longNull.isNumericNull());
Assert.assertEquals(NullHandling.sqlCompatible(), doubleNull.isNumericNull());
Assert.assertEquals(NullHandling.defaultLongValue(), longNull.valueOrDefault());
Assert.assertEquals(NullHandling.defaultDoubleValue(), doubleNull.valueOrDefault());
if (NullHandling.replaceWithDefault()) {
Assert.assertEquals(0L, longNull.asLong());
Assert.assertEquals(0, longNull.asInt());
Assert.assertEquals(0.0, longNull.asDouble(), 0.0);
Assert.assertEquals(0L, doubleNull.asLong());
Assert.assertEquals(0, doubleNull.asInt());
Assert.assertEquals(0.0, doubleNull.asDouble(), 0.0);
}
}
@Test
public void testEvalOfType()
{
// strings
ExprEval eval = ExprEval.ofType(ExpressionType.STRING, "stringy");
Assert.assertEquals(ExpressionType.STRING, eval.type());
Assert.assertEquals("stringy", eval.value());
eval = ExprEval.ofType(ExpressionType.STRING, 1L);
Assert.assertEquals(ExpressionType.STRING, eval.type());
Assert.assertEquals("1", eval.value());
eval = ExprEval.ofType(ExpressionType.STRING, 1.0);
Assert.assertEquals(ExpressionType.STRING, eval.type());
Assert.assertEquals("1.0", eval.value());
eval = ExprEval.ofType(ExpressionType.STRING, true);
Assert.assertEquals(ExpressionType.STRING, eval.type());
Assert.assertEquals("true", eval.value());
// strings might also be liars and arrays or lists
eval = ExprEval.ofType(ExpressionType.STRING, new Object[]{"a", "b", "c"});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{"a", "b", "c"}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING, new String[]{"a", "b", "c"});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{"a", "b", "c"}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING, Arrays.asList("a", "b", "c"));
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{"a", "b", "c"}, (Object[]) eval.value());
// longs
eval = ExprEval.ofType(ExpressionType.LONG, 1L);
Assert.assertEquals(ExpressionType.LONG, eval.type());
Assert.assertEquals(1L, eval.value());
eval = ExprEval.ofType(ExpressionType.LONG, 1.0);
Assert.assertEquals(ExpressionType.LONG, eval.type());
Assert.assertEquals(1L, eval.value());
eval = ExprEval.ofType(ExpressionType.LONG, "1");
Assert.assertEquals(ExpressionType.LONG, eval.type());
Assert.assertEquals(1L, eval.value());
eval = ExprEval.ofType(ExpressionType.LONG, true);
Assert.assertEquals(ExpressionType.LONG, eval.type());
Assert.assertEquals(1L, eval.value());
// doubles
eval = ExprEval.ofType(ExpressionType.DOUBLE, 1L);
Assert.assertEquals(ExpressionType.DOUBLE, eval.type());
Assert.assertEquals(1.0, eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE, 1.0);
Assert.assertEquals(ExpressionType.DOUBLE, eval.type());
Assert.assertEquals(1.0, eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE, "1");
Assert.assertEquals(ExpressionType.DOUBLE, eval.type());
Assert.assertEquals(1.0, eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE, true);
Assert.assertEquals(ExpressionType.DOUBLE, eval.type());
Assert.assertEquals(1.0, eval.value());
// complex
TypeStrategiesTest.NullableLongPair pair = new TypeStrategiesTest.NullableLongPair(1L, 2L);
ExpressionType type = ExpressionType.fromColumnType(TypeStrategiesTest.NULLABLE_TEST_PAIR_TYPE);
eval = ExprEval.ofType(type, pair);
Assert.assertEquals(type, eval.type());
Assert.assertEquals(pair, eval.value());
ByteBuffer buffer = ByteBuffer.allocate(TypeStrategiesTest.NULLABLE_TEST_PAIR_TYPE.getStrategy().estimateSizeBytes(pair));
TypeStrategiesTest.NULLABLE_TEST_PAIR_TYPE.getStrategy().write(buffer, pair, buffer.limit());
byte[] pairBytes = buffer.array();
eval = ExprEval.ofType(type, pairBytes);
Assert.assertEquals(type, eval.type());
Assert.assertEquals(pair, eval.value());
eval = ExprEval.ofType(type, StringUtils.encodeBase64String(pairBytes));
Assert.assertEquals(type, eval.type());
Assert.assertEquals(pair, eval.value());
// json type best efforts its way to other types
eval = ExprEval.ofType(ExpressionType.NESTED_DATA, ImmutableMap.of("x", 1L, "y", 2L));
Assert.assertEquals(ExpressionType.NESTED_DATA, eval.type());
Assert.assertEquals(ImmutableMap.of("x", 1L, "y", 2L), eval.value());
ExpressionType stringyComplexThing = ExpressionType.fromString("COMPLEX<somestringything>");
eval = ExprEval.ofType(stringyComplexThing, "notbase64");
Assert.assertEquals(stringyComplexThing, eval.type());
Assert.assertEquals("notbase64", eval.value());
// arrays
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, ImmutableList.of(1L, 2L, 3L));
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Long[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new long[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new int[]{1, 2, 3});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, null, 3L});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, null, 3L}, (Object[]) eval.value());
// arrays might have to fall back to using 'bestEffortOf', but will cast it to the expected output type
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{"1", "2", "3"});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new String[]{"1", "2", "3"});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{"1", "2", "wat", "3"});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, null, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new double[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1.0, 2.0, null, 3.0});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, null, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1.0, 2L, "3", true, false});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L, 1L, 0L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new float[]{1.0f, 2.0f, 3.0f});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
// etc
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Double[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new double[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{"1", "2", "3"});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{"1", "2", "wat", "3"});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, null, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new long[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{1L, 2L, null, 3L});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, null, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2L, "3", true, false});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0, 1.0, 0.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Float[]{1.0f, 2.0f, 3.0f});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new float[]{1.0f, 2.0f, 3.0f});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[]{"1", "2", "3"});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{"1", "2", "3"}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{"1", "2", "3"}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{"1.0", "2.0", "3.0"}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[]{1.0, 2L, "3", true, false});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[]{"1.0", "2", "3", "true", "false"}, (Object[]) eval.value());
// nested arrays
ExpressionType nestedLongArray = ExpressionTypeFactory.getInstance().ofArray(ExpressionType.LONG_ARRAY);
final Object[] expectedLongArray = new Object[]{
new Object[]{1L, 2L, 3L},
new Object[]{5L, null, 9L},
null,
new Object[]{2L, 4L, 6L}
};
List<?> longArrayInputs = Arrays.asList(
new Object[]{
new Object[]{1L, 2L, 3L},
new Object[]{5L, null, 9L},
null,
new Object[]{2L, 4L, 6L}
},
Arrays.asList(
new Object[]{1L, 2L, 3L},
new Object[]{5L, null, 9L},
null,
new Object[]{2L, 4L, 6L}
),
Arrays.asList(
Arrays.asList(1L, 2L, 3L),
Arrays.asList(5L, null, 9L),
null,
Arrays.asList(2L, 4L, 6L)
),
Arrays.asList(
Arrays.asList(1L, 2L, 3L),
Arrays.asList("5", "hello", "9"),
null,
new Object[]{2.2, 4.4, 6.6}
)
);
for (Object o : longArrayInputs) {
eval = ExprEval.ofType(nestedLongArray, o);
Assert.assertEquals(nestedLongArray, eval.type());
Object[] val = (Object[]) eval.value();
Assert.assertEquals(expectedLongArray.length, val.length);
for (int i = 0; i < expectedLongArray.length; i++) {
Assert.assertArrayEquals((Object[]) expectedLongArray[i], (Object[]) val[i]);
}
}
ExpressionType nestedDoubleArray = ExpressionTypeFactory.getInstance().ofArray(ExpressionType.DOUBLE_ARRAY);
final Object[] expectedDoubleArray = new Object[]{
new Object[]{1.1, 2.2, 3.3},
new Object[]{5.5, null, 9.9},
null,
new Object[]{2.2, 4.4, 6.6}
};
List<?> doubleArrayInputs = Arrays.asList(
new Object[]{
new Object[]{1.1, 2.2, 3.3},
new Object[]{5.5, null, 9.9},
null,
new Object[]{2.2, 4.4, 6.6}
},
new Object[]{
Arrays.asList(1.1, 2.2, 3.3),
Arrays.asList(5.5, null, 9.9),
null,
Arrays.asList(2.2, 4.4, 6.6)
},
Arrays.asList(
Arrays.asList(1.1, 2.2, 3.3),
Arrays.asList(5.5, null, 9.9),
null,
Arrays.asList(2.2, 4.4, 6.6)
),
new Object[]{
new Object[]{"1.1", "2.2", "3.3"},
Arrays.asList("5.5", null, "9.9"),
null,
new String[]{"2.2", "4.4", "6.6"}
}
);
for (Object o : doubleArrayInputs) {
eval = ExprEval.ofType(nestedDoubleArray, o);
Assert.assertEquals(nestedDoubleArray, eval.type());
Object[] val = (Object[]) eval.value();
Assert.assertEquals(expectedLongArray.length, val.length);
for (int i = 0; i < expectedLongArray.length; i++) {
Assert.assertArrayEquals((Object[]) expectedDoubleArray[i], (Object[]) val[i]);
}
}
}
@Test
public void testBestEffortOf()
{
// strings
assertBestEffortOf("stringy", ExpressionType.STRING, "stringy");
assertBestEffortOf(
new byte[]{1, 2, 3, 4},
ExpressionType.STRING,
StringUtils.encodeBase64String(new byte[]{1, 2, 3, 4})
);
// longs
assertBestEffortOf(1L, ExpressionType.LONG, 1L);
assertBestEffortOf(1, ExpressionType.LONG, 1L);
// by default, booleans are handled as longs
assertBestEffortOf(true, ExpressionType.LONG, 1L);
assertBestEffortOf(Arrays.asList(true, false), ExpressionType.LONG_ARRAY, new Object[]{1L, 0L});
try {
// in non-strict boolean mode, they are strings
ExpressionProcessing.initializeForStrictBooleansTests(false);
assertBestEffortOf(true, ExpressionType.STRING, "true");
assertBestEffortOf(Arrays.asList(true, false), ExpressionType.STRING_ARRAY, new Object[]{"true", "false"});
}
finally {
// reset
ExpressionProcessing.initializeForTests();
}
// doubles
assertBestEffortOf(1.0, ExpressionType.DOUBLE, 1.0);
assertBestEffortOf(1.0f, ExpressionType.DOUBLE, 1.0);
// arrays
assertBestEffortOf(new Object[]{1L, 2L, 3L}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new Object[]{1L, 2L, null, 3L}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, null, 3L});
assertBestEffortOf(ImmutableList.of(1L, 2L, 3L), ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new long[]{1L, 2L, 3L}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new Object[]{1, 2, 3}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new Integer[]{1, 2, 3}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new int[]{1, 2, 3}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new Object[]{1.0, 2.0, 3.0}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(
new Object[]{null, 1.0, 2.0, 3.0},
ExpressionType.DOUBLE_ARRAY,
new Object[]{null, 1.0, 2.0, 3.0}
);
assertBestEffortOf(new Double[]{1.0, 2.0, 3.0}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new double[]{1.0, 2.0, 3.0}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new Object[]{1.0f, 2.0f, 3.0f}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new Float[]{1.0f, 2.0f, 3.0f}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new float[]{1.0f, 2.0f, 3.0f}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new Object[]{"1", "2", "3"}, ExpressionType.STRING_ARRAY, new Object[]{"1", "2", "3"});
assertBestEffortOf(new String[]{"1", "2", "3"}, ExpressionType.STRING_ARRAY, new Object[]{"1", "2", "3"});
assertBestEffortOf(ImmutableList.of("1", "2", "3"), ExpressionType.STRING_ARRAY, new Object[]{"1", "2", "3"});
// arrays end up as the least restrictive type
assertBestEffortOf(new Object[]{1.0, 2L}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0});
// arrays end up as the least restrictive type
assertBestEffortOf(
new Object[]{1.0, 2L, "3", true, false},
ExpressionType.STRING_ARRAY,
new Object[]{"1.0", "2", "3", "true", "false"}
);
assertBestEffortOf(
ImmutableMap.of("x", 1L, "y", 2L),
ExpressionType.NESTED_DATA,
ImmutableMap.of("x", 1L, "y", 2L)
);
SerializablePair<String, Long> someOtherComplex = new SerializablePair<>("hello", 1234L);
assertBestEffortOf(
someOtherComplex,
ExpressionType.UNKNOWN_COMPLEX,
someOtherComplex
);
}
private void assertBestEffortOf(@Nullable Object val, ExpressionType expectedType, @Nullable Object expectedValue)
{
ExprEval eval = ExprEval.bestEffortOf(val);
Assert.assertEquals(expectedType, eval.type());
if (eval.type().isArray()) {
Assert.assertArrayEquals((Object[]) expectedValue, eval.asArray());
} else {
Assert.assertEquals(expectedValue, eval.value());
}
// make sure that ofType matches bestEffortOf
eval = ExprEval.ofType(eval.type(), val);
Assert.assertEquals(expectedType, eval.type());
if (eval.type().isArray()) {
Assert.assertArrayEquals((Object[]) expectedValue, eval.asArray());
} else {
Assert.assertEquals(expectedValue, eval.value());
}
}
}