blob: f2e832f8c672b57f2cca8bc378440a47c6140120 [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.parquet.util;
import org.apache.parquet.TestUtils;
import org.apache.parquet.util.Concatenator.SomeCheckedException;
import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.Callable;
public class TestDynMethods {
@Test
public void testNoImplCall() {
final DynMethods.Builder builder = new DynMethods.Builder("concat");
TestUtils.assertThrows("Checked build should throw NoSuchMethodException",
NoSuchMethodException.class, (Callable) builder::buildChecked);
TestUtils.assertThrows("Normal build should throw RuntimeException",
RuntimeException.class, (Callable) builder::build);
}
@Test
public void testMissingClass() {
final DynMethods.Builder builder = new DynMethods.Builder("concat")
.impl("not.a.RealClass", String.class, String.class);
TestUtils.assertThrows("Checked build should throw NoSuchMethodException",
NoSuchMethodException.class, (Callable) builder::buildChecked);
TestUtils.assertThrows("Normal build should throw RuntimeException",
RuntimeException.class, (Runnable) builder::build);
}
@Test
public void testMissingMethod() {
final DynMethods.Builder builder = new DynMethods.Builder("concat")
.impl(Concatenator.class, "cat2strings", String.class, String.class);
TestUtils.assertThrows("Checked build should throw NoSuchMethodException",
NoSuchMethodException.class, (Callable) builder::buildChecked);
TestUtils.assertThrows("Normal build should throw RuntimeException",
RuntimeException.class, (Runnable) builder::build);
}
@Test
public void testFirstImplReturned() throws Exception {
Concatenator obj = new Concatenator("-");
DynMethods.UnboundMethod cat2 = new DynMethods.Builder("concat")
.impl("not.a.RealClass", String.class, String.class)
.impl(Concatenator.class, String.class, String.class)
.impl(Concatenator.class, String.class, String.class, String.class)
.buildChecked();
Assert.assertEquals("Should call the 2-arg version successfully",
"a-b", cat2.invoke(obj, "a", "b"));
Assert.assertEquals("Should ignore extra arguments",
"a-b", cat2.invoke(obj, "a", "b", "c"));
DynMethods.UnboundMethod cat3 = new DynMethods.Builder("concat")
.impl("not.a.RealClass", String.class, String.class)
.impl(Concatenator.class, String.class, String.class, String.class)
.impl(Concatenator.class, String.class, String.class)
.build();
Assert.assertEquals("Should call the 3-arg version successfully",
"a-b-c", cat3.invoke(obj, "a", "b", "c"));
Assert.assertEquals("Should call the 3-arg version null padding",
"a-b-null", cat3.invoke(obj, "a", "b"));
}
@Test
public void testVarArgs() throws Exception {
DynMethods.UnboundMethod cat = new DynMethods.Builder("concat")
.impl(Concatenator.class, String[].class)
.buildChecked();
Assert.assertEquals("Should use the varargs version", "abcde",
cat.invokeChecked(
new Concatenator(),
(Object) new String[] {"a", "b", "c", "d", "e"}));
Assert.assertEquals("Should use the varargs version", "abcde",
cat.bind(new Concatenator())
.invokeChecked((Object) new String[] {"a", "b", "c", "d", "e"}));
}
@Test
public void testIncorrectArguments() throws Exception {
final Concatenator obj = new Concatenator("-");
final DynMethods.UnboundMethod cat = new DynMethods.Builder("concat")
.impl("not.a.RealClass", String.class, String.class)
.impl(Concatenator.class, String.class, String.class)
.buildChecked();
TestUtils.assertThrows("Should fail if non-string arguments are passed",
IllegalArgumentException.class, () -> cat.invoke(obj, 3, 4));
TestUtils.assertThrows("Should fail if non-string arguments are passed",
IllegalArgumentException.class, () -> cat.invokeChecked(obj, 3, 4));
}
@Test
public void testExceptionThrown() throws Exception {
final SomeCheckedException exc = new SomeCheckedException();
final Concatenator obj = new Concatenator("-");
final DynMethods.UnboundMethod cat = new DynMethods.Builder("concat")
.impl("not.a.RealClass", String.class, String.class)
.impl(Concatenator.class, Exception.class)
.buildChecked();
TestUtils.assertThrows("Should re-throw the exception",
SomeCheckedException.class, () -> cat.invokeChecked(obj, exc));
TestUtils.assertThrows("Should wrap the exception in RuntimeException",
RuntimeException.class, () -> cat.invoke(obj, exc));
}
@Test
public void testNameChange() throws Exception {
Concatenator obj = new Concatenator("-");
DynMethods.UnboundMethod cat = new DynMethods.Builder("cat")
.impl(Concatenator.class, "concat", String.class, String.class)
.buildChecked();
Assert.assertEquals("Should find 2-arg concat method",
"a-b", cat.invoke(obj, "a", "b"));
}
@Test
public void testStringClassname() throws Exception {
Concatenator obj = new Concatenator("-");
DynMethods.UnboundMethod cat = new DynMethods.Builder("concat")
.impl(Concatenator.class.getName(), String.class, String.class)
.buildChecked();
Assert.assertEquals("Should find 2-arg concat method",
"a-b", cat.invoke(obj, "a", "b"));
}
@Test
public void testHiddenMethod() throws Exception {
Concatenator obj = new Concatenator("-");
TestUtils.assertThrows("Should fail to find hidden method",
NoSuchMethodException.class, () -> new DynMethods.Builder("setSeparator")
.impl(Concatenator.class, String.class)
.buildChecked());
DynMethods.UnboundMethod changeSep = new DynMethods.Builder("setSeparator")
.hiddenImpl(Concatenator.class, String.class)
.buildChecked();
Assert.assertNotNull("Should find hidden method with hiddenImpl",
changeSep);
changeSep.invokeChecked(obj, "/");
Assert.assertEquals("Should use separator / instead of -",
"a/b", obj.concat("a", "b"));
}
@Test
public void testBoundMethod() throws Exception {
DynMethods.UnboundMethod cat = new DynMethods.Builder("concat")
.impl(Concatenator.class, String.class, String.class)
.buildChecked();
// Unbound methods can be bound multiple times
DynMethods.BoundMethod dashCat = cat.bind(new Concatenator("-"));
DynMethods.BoundMethod underCat = cat.bind(new Concatenator("_"));
Assert.assertEquals("Should use '-' object without passing",
"a-b", dashCat.invoke("a", "b"));
Assert.assertEquals("Should use '_' object without passing",
"a_b", underCat.invoke("a", "b"));
DynMethods.BoundMethod slashCat = new DynMethods.Builder("concat")
.impl(Concatenator.class, String.class, String.class)
.buildChecked(new Concatenator("/"));
Assert.assertEquals("Should use bound object from builder without passing",
"a/b", slashCat.invoke("a", "b"));
}
@Test
public void testBindStaticMethod() throws Exception {
final DynMethods.Builder builder = new DynMethods.Builder("cat")
.impl(Concatenator.class, String[].class);
TestUtils.assertThrows("Should complain that method is static",
IllegalStateException.class, () -> builder.buildChecked(new Concatenator()));
TestUtils.assertThrows("Should complain that method is static",
IllegalStateException.class, () -> builder.build(new Concatenator()));
final DynMethods.UnboundMethod staticCat = builder.buildChecked();
Assert.assertTrue("Should be static", staticCat.isStatic());
TestUtils.assertThrows("Should complain that method is static",
IllegalStateException.class, () -> staticCat.bind(new Concatenator()));
}
@Test
public void testStaticMethod() throws Exception {
DynMethods.StaticMethod staticCat = new DynMethods.Builder("cat")
.impl(Concatenator.class, String[].class)
.buildStaticChecked();
Assert.assertEquals("Should call varargs static method cat(String...)",
"abcde", staticCat.invokeChecked(
(Object) new String[] {"a", "b", "c", "d", "e"}));
}
@Test
public void testNonStaticMethod() throws Exception {
final DynMethods.Builder builder = new DynMethods.Builder("concat")
.impl(Concatenator.class, String.class, String.class);
TestUtils.assertThrows("Should complain that method is not static",
IllegalStateException.class, builder::buildStatic);
TestUtils.assertThrows("Should complain that method is not static",
IllegalStateException.class, builder::buildStaticChecked);
final DynMethods.UnboundMethod cat2 = builder.buildChecked();
Assert.assertFalse("concat(String,String) should not be static",
cat2.isStatic());
TestUtils.assertThrows("Should complain that method is not static",
IllegalStateException.class, cat2::asStatic);
}
@Test
public void testConstructorImpl() throws Exception {
final DynMethods.Builder builder = new DynMethods.Builder("newConcatenator")
.ctorImpl(Concatenator.class, String.class)
.impl(Concatenator.class, String.class);
DynMethods.UnboundMethod newConcatenator = builder.buildChecked();
Assert.assertTrue("Should find constructor implementation",
newConcatenator instanceof DynConstructors.Ctor);
Assert.assertTrue("Constructor should be a static method",
newConcatenator.isStatic());
Assert.assertFalse("Constructor should not be NOOP",
newConcatenator.isNoop());
// constructors cannot be bound
TestUtils.assertThrows("Should complain that ctor method is static",
IllegalStateException.class, () -> builder.buildChecked(new Concatenator()));
TestUtils.assertThrows("Should complain that ctor method is static",
IllegalStateException.class, () -> builder.build(new Concatenator()));
Concatenator concatenator = newConcatenator.asStatic().invoke("*");
Assert.assertEquals("Should function as a concatenator",
"a*b", concatenator.concat("a", "b"));
concatenator = newConcatenator.asStatic().invokeChecked("@");
Assert.assertEquals("Should function as a concatenator",
"a@b", concatenator.concat("a", "b"));
}
@Test
public void testConstructorImplAfterFactoryMethod() throws Exception {
DynMethods.UnboundMethod newConcatenator = new DynMethods.Builder("newConcatenator")
.impl(Concatenator.class, String.class)
.ctorImpl(Concatenator.class, String.class)
.buildChecked();
Assert.assertFalse("Should find factory method before constructor method",
newConcatenator instanceof DynConstructors.Ctor);
}
@Test
public void testNoop() throws Exception {
// noop can be unbound, bound, or static
DynMethods.UnboundMethod noop = new DynMethods.Builder("concat")
.impl("not.a.RealClass", String.class, String.class)
.orNoop()
.buildChecked();
Assert.assertTrue("No implementation found, should return NOOP",
noop.isNoop());
Assert.assertNull("NOOP should always return null",
noop.invoke(new Concatenator(), "a"));
Assert.assertNull("NOOP can be called with null",
noop.invoke(null, "a"));
Assert.assertNull("NOOP can be bound",
noop.bind(new Concatenator()).invoke("a"));
Assert.assertNull("NOOP can be bound to null",
noop.bind(null).invoke("a"));
Assert.assertNull("NOOP can be static",
noop.asStatic().invoke("a"));
}
}