blob: 75adbabe911ba4006fc49ada233384ffb29d1ffe [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.calcite.avatica.test;
import org.apache.calcite.avatica.AvaticaUtils;
import org.apache.calcite.avatica.ConnectionConfigImpl;
import org.apache.calcite.avatica.ConnectionProperty;
import org.apache.calcite.avatica.util.ByteString;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Properties;
import java.util.Set;
import static org.apache.calcite.avatica.AvaticaUtils.skipFully;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
/**
* Unit test for Avatica utilities.
*/
public class AvaticaUtilsTest {
@Test public void testInstantiatePlugin() {
final String s =
AvaticaUtils.instantiatePlugin(String.class, "java.lang.String");
assertThat(s, is(""));
// No default constructor or INSTANCE member
try {
final Integer i =
AvaticaUtils.instantiatePlugin(Integer.class, "java.lang.Integer");
fail("expected error, got " + i);
} catch (Throwable e) {
assertThat(e.getMessage(),
is("Property 'java.lang.Integer' not valid for plugin type java.lang.Integer"));
}
final BigInteger b =
AvaticaUtils.instantiatePlugin(BigInteger.class, "java.math.BigInteger#ONE");
assertThat(b, is(BigInteger.ONE));
try {
final BigInteger b2 =
AvaticaUtils.instantiatePlugin(BigInteger.class,
"java.math.BigInteger.ONE");
fail("expected error, got " + b2);
} catch (Throwable e) {
assertThat(e.getMessage(),
is("Property 'java.math.BigInteger.ONE' not valid for plugin type java.math.BigInteger"));
}
}
/** Unit test for
* {@link org.apache.calcite.avatica.AvaticaUtils#unique(java.lang.String)}. */
@Test public void testUnique() {
// Below, the "probably" comments indicate the strings that will be
// generated the first time you run the test.
final Set<String> list = new LinkedHashSet<>();
list.add(AvaticaUtils.unique("a")); // probably "a"
assertThat(list.size(), is(1));
list.add(AvaticaUtils.unique("a")); // probably "a_1"
assertThat(list.size(), is(2));
list.add(AvaticaUtils.unique("b")); // probably "b"
assertThat(list.size(), is(3));
list.add(AvaticaUtils.unique("a_1")); // probably "a_1_3"
assertThat(list.size(), is(4));
list.add(AvaticaUtils.unique("A")); // probably "A"
assertThat(list.size(), is(5));
list.add(AvaticaUtils.unique("a")); // probably "a_5"
assertThat(list.size(), is(6));
}
/** Tests connect string properties. */
@Test public void testConnectionProperty() {
final ConnectionPropertyImpl n = new ConnectionPropertyImpl("N",
BigDecimal.valueOf(100), ConnectionProperty.Type.NUMBER);
final Properties properties = new Properties();
ConnectionConfigImpl.PropEnv env = n.wrap(properties);
assertThat(env.getInt(), is(100));
assertThat(env.getInt(-45), is(-45));
properties.setProperty(n.name, "123");
assertThat(env.getInt(), is(100));
env = n.wrap(properties);
assertThat(env.getInt(), is(123));
assertThat(env.getInt(-45), is(123));
properties.setProperty(n.name, "10k");
env = n.wrap(properties);
assertThat(env.getInt(), is(10 * 1024));
properties.setProperty(n.name, "-0.5k");
env = n.wrap(properties);
assertThat(env.getInt(), is(-512));
properties.setProperty(n.name, "10m");
env = n.wrap(properties);
assertThat(env.getInt(), is(10 * 1024 * 1024));
assertThat(env.getLong(), is(10L * 1024 * 1024));
assertThat(env.getDouble(), is(10D * 1024 * 1024));
properties.setProperty(n.name, "-2M");
env = n.wrap(properties);
assertThat(env.getInt(), is(-2 * 1024 * 1024));
properties.setProperty(n.name, "10g");
env = n.wrap(properties);
assertThat(env.getLong(), is(10L * 1024 * 1024 * 1024));
final ConnectionPropertyImpl b = new ConnectionPropertyImpl("B",
true, ConnectionProperty.Type.BOOLEAN);
env = b.wrap(properties);
assertThat(env.getBoolean(), is(true));
assertThat(env.getBoolean(true), is(true));
assertThat(env.getBoolean(false), is(false));
properties.setProperty(b.name, "false");
env = b.wrap(properties);
assertThat(env.getBoolean(), is(false));
final ConnectionPropertyImpl s = new ConnectionPropertyImpl("S",
"foo", ConnectionProperty.Type.STRING);
env = s.wrap(properties);
assertThat(env.getString(), is("foo"));
assertThat(env.getString("baz"), is("baz"));
properties.setProperty(s.name, " ");
env = s.wrap(properties);
assertThat(env.getString(), is(" "));
try {
final ConnectionPropertyImpl t =
new ConnectionPropertyImpl("T", null, ConnectionProperty.Type.ENUM);
fail("should throw if you specify an enum property without a class, got "
+ t);
} catch (AssertionError e) {
assertThat(e.getMessage(), is("must specify value class for an ENUM"));
// ok
}
// An enum with a default value
final ConnectionPropertyImpl t = new ConnectionPropertyImpl("T", Size.BIG,
ConnectionProperty.Type.ENUM, Size.class);
env = t.wrap(properties);
assertThat(env.getEnum(Size.class), is(Size.BIG));
assertThat(env.getEnum(Size.class, Size.SMALL), is(Size.SMALL));
assertThat(env.getEnum(Size.class, null), nullValue());
try {
final Weight envEnum = env.getEnum(Weight.class, null);
fail("expected error, got " + envEnum);
} catch (AssertionError e) {
assertThat(e.getMessage(),
is("wrong value class; expected " + Size.class));
}
// An enum with a default value that is an anonymous enum,
// not specifying value type.
final ConnectionPropertyImpl v = new ConnectionPropertyImpl("V",
Size.SMALL, ConnectionProperty.Type.ENUM);
env = v.wrap(properties);
assertThat(env.getEnum(Size.class), is(Size.SMALL));
assertThat(env.getEnum(Size.class, Size.BIG), is(Size.BIG));
assertThat(env.getEnum(Size.class, null), nullValue());
try {
final Weight envEnum = env.getEnum(Weight.class, null);
fail("expected error, got " + envEnum);
} catch (AssertionError e) {
assertThat(e.getMessage(),
is("wrong value class; expected " + Size.class));
}
// An enum with no default value
final ConnectionPropertyImpl u = new ConnectionPropertyImpl("U", null,
ConnectionProperty.Type.ENUM, Size.class);
env = u.wrap(properties);
assertThat(env.getEnum(Size.class), nullValue());
assertThat(env.getEnum(Size.class, Size.SMALL), is(Size.SMALL));
assertThat(env.getEnum(Size.class, null), nullValue());
try {
final Weight envEnum = env.getEnum(Weight.class, null);
fail("expected error, got " + envEnum);
} catch (AssertionError e) {
assertThat(e.getMessage(),
is("wrong value class; expected " + Size.class));
}
}
@Test public void testLongToIntegerTranslation() {
long[] longValues = new long[] {Integer.MIN_VALUE, -5, 0, 1, Integer.MAX_VALUE,
((long) Integer.MAX_VALUE) + 1L, Long.MAX_VALUE};
int[] convertedValues = AvaticaUtils.toSaturatedInts(longValues);
int[] intValues = new int[] {Integer.MIN_VALUE, -5, 0, 1, Integer.MAX_VALUE,
Integer.MAX_VALUE, Integer.MAX_VALUE};
assertArrayEquals(convertedValues, intValues);
}
@Test public void testByteString() {
final byte[] bytes = {3, 14, 15, 92, 0, 65, 35, 0};
final ByteString s = new ByteString(bytes);
final ByteString s2 = new ByteString(bytes.clone());
final ByteString s3 = new ByteString(new byte[0]);
final ByteString s4 = new ByteString(new byte[] {0});
final ByteString s5 = new ByteString(new byte[]{15, 92});
// length
assertThat(s.length(), is(8));
assertThat(s3.length(), is(0));
assertThat(s4.length(), is(1));
// equals and hashCode
assertThat(s.hashCode(), is(s2.hashCode()));
assertThat(s.equals(s2), is(true));
assertThat(s2.equals(s), is(true));
assertThat(s.equals(s3), is(false));
assertThat(s3.equals(s), is(false));
// toString
assertThat(s.toString(), is("030e0f5c00412300"));
assertThat(s3.toString(), is(""));
assertThat(s4.toString(), is("00"));
// indexOf
assertThat(s.indexOf(s3), is(0));
assertThat(s.indexOf(s3, 5), is(5));
assertThat(s.indexOf(s3, 15), is(-1));
assertThat(s.indexOf(s4), is(4));
assertThat(s.indexOf(s4, 4), is(4));
assertThat(s.indexOf(s4, 5), is(7));
assertThat(s.indexOf(s5), is(2));
assertThat(s.indexOf(s5, 2), is(2));
assertThat(s.indexOf(s5, 3), is(-1));
assertThat(s.indexOf(s5, 7), is(-1));
// substring
assertThat(s.substring(8), is(s3));
assertThat(s.substring(7), is(s4));
assertThat(s.substring(0), is(s));
// getBytes
assertThat(s.getBytes().length, is(8));
assertThat(Arrays.equals(s.getBytes(), bytes), is(true));
assertThat(s.getBytes()[3], is((byte) 92));
final byte[] copyBytes = s.getBytes();
copyBytes[3] = 11;
assertThat(s.getBytes()[3], is((byte) 92));
assertThat(s, is(s2));
}
@Test public void testSkipFully() throws IOException {
InputStream in = of("");
assertEquals(0, in.available());
skipFully(in);
assertEquals(0, in.available());
in = of("asdf");
assertEquals(4, in.available());
skipFully(in);
assertEquals(0, in.available());
in = of("asdfasdf");
for (int i = 0; i < 4; i++) {
assertNotEquals(-1, in.read());
}
assertEquals(4, in.available());
skipFully(in);
assertEquals(0, in.available());
}
/** Returns an InputStream of UTF-8 encoded bytes from the provided string */
InputStream of(String str) {
return new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8));
}
/** Dummy implementation of {@link ConnectionProperty}. */
private static class ConnectionPropertyImpl implements ConnectionProperty {
private final String name;
private final Object defaultValue;
private final Class<?> valueClass;
private Type type;
ConnectionPropertyImpl(String name, Object defaultValue, Type type) {
this(name, defaultValue, type, null);
}
ConnectionPropertyImpl(String name, Object defaultValue, Type type,
Class valueClass) {
this.name = name;
this.defaultValue = defaultValue;
this.type = type;
this.valueClass = type.deduceValueClass(defaultValue, valueClass);
if (!type.valid(defaultValue, this.valueClass)) {
throw new AssertionError(name);
}
}
public String name() {
return name.toUpperCase(Locale.ROOT);
}
public String camelName() {
return name.toLowerCase(Locale.ROOT);
}
public Object defaultValue() {
return defaultValue;
}
public Type type() {
return type;
}
public Class valueClass() {
return valueClass;
}
public ConnectionConfigImpl.PropEnv wrap(Properties properties) {
final HashMap<String, ConnectionProperty> map = new HashMap<>();
map.put(name, this);
return new ConnectionConfigImpl.PropEnv(
ConnectionConfigImpl.parse(properties, map), this);
}
public boolean required() {
return false;
}
}
/** How large? */
private enum Size {
BIG,
SMALL {
}
}
/** How heavy? */
private enum Weight {
HEAVY, LIGHT
}
}
// End AvaticaUtilsTest.java