/*
* Copyright (C) 2011 Red Hat, Inc. and/or its affiliates.
*
* Licensed 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.jboss.errai.codegen.test;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.jboss.errai.codegen.Context;
import org.jboss.errai.codegen.Variable;
import org.jboss.errai.codegen.builder.impl.ContextBuilder;
import org.jboss.errai.codegen.builder.impl.StatementBuilder;
import org.jboss.errai.codegen.exception.InvalidTypeException;
import org.jboss.errai.codegen.exception.OutOfScopeException;
import org.jboss.errai.codegen.exception.UndefinedMethodException;
import org.jboss.errai.codegen.meta.MetaClass;
import org.jboss.errai.codegen.meta.MetaClassFactory;
import org.jboss.errai.codegen.meta.MetaMethod;
import org.jboss.errai.codegen.test.model.Foo;
import org.jboss.errai.codegen.util.Refs;
import org.junit.Test;
import javax.enterprise.util.TypeLiteral;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Tests the generation of method invocations using the {@link StatementBuilder} API.
*
* @author Christian Sadilek <csadilek@redhat.com>
*/
@SuppressWarnings("serial")
public class InvocationBuilderTest extends AbstractCodegenTest {
@Test
public void testSingleInvocation() {
String s = StatementBuilder.create()
.declareVariable("obj", Object.class)
.loadVariable("obj")
.invoke("toString")
.toJavaString();
assertEquals("Failed to generate invocation on variable", "obj.toString()", s);
}
@Test
public void testChainedInvocations() {
String s = StatementBuilder.create()
.declareVariable("i", Integer.class)
.declareVariable("regex", String.class)
.declareVariable("replacement", String.class)
.loadVariable("i")
.invoke("toString")
.invoke("replaceAll", Variable.get("regex"), Variable.get("replacement"))
.toJavaString();
assertEquals("Failed to generate chained invocations on variable",
"i.toString().replaceAll(regex, replacement)", s);
}
@Test
public void testInvokeWithLiteralParameters() {
String result = StatementBuilder.create().declareVariable("s", String.class)
.loadVariable("s").invoke("replaceAll", "foo", "foo\t\n").toJavaString();
assertEquals("Failed to generate invocation using literal parameters",
"s.replaceAll(\"foo\", \"foo\\t\\n\")", result);
}
@Test
public void testInvokeOnLiteral() {
String result = StatementBuilder.create().loadLiteral("foo").invoke("toString").toJavaString();
assertEquals("Failed to generate invocation using literal parameters",
"\"foo\".toString()", result);
}
@Test
public void testInvokeBestMatchingMethod() {
String s = StatementBuilder.create()
.declareVariable("n", Integer.class)
.loadVariable("n")
// 1 will be inferred to LiteralValue<Integer>, equals(Integer.class)
// should be matched equals(Object.class)
.invoke("equals", 1)
.toJavaString();
assertEquals("Failed to generate invocation on matched method", "n.equals(1)", s);
}
@Test
public void testInvokeUndefinedMethodOnVariable() {
try {
StatementBuilder.create()
.declareVariable("obj", Object.class)
.declareVariable("param", String.class)
.loadVariable("obj")
.invoke("undefinedMethod", Variable.get("param"))
.toJavaString();
fail("expected UndefinedMethodException");
}
catch (UndefinedMethodException udme) {
// expected
assertEquals("Wrong exception thrown", udme.getMethodName(), "undefinedMethod");
}
}
@Test
public void testInvokeChainedUndefinedMethod() {
try {
StatementBuilder.create()
.declareVariable("s", String.class)
.declareVariable("regex", String.class)
.declareVariable("replacement", String.class)
.loadVariable("s")
.invoke("replaceAll", Variable.get("regex"), Variable.get("replacement"))
.invoke("undefinedMethod", Variable.get("regex"), Variable.get("replacement"))
.toJavaString();
fail("expected UndefinedMethodException");
}
catch (UndefinedMethodException udme) {
// expected
assertEquals("Wrong exception thrown", udme.getMethodName(), "undefinedMethod");
}
}
@Test
public void testInvokeOnUndefinedVariable() {
try {
// injector undefined
StatementBuilder.create()
.loadVariable("injector")
.invoke("provide", Refs.get("param"), Refs.get("param2"))
.toJavaString();
fail("expected OutOfScopeException");
}
catch (OutOfScopeException oose) {
// expected
assertTrue("Wrong exception thrown", oose.getMessage().contains("injector"));
}
}
@Test
public void testInvokeWithUndefinedVariable() {
try {
// param2 undefined
StatementBuilder.create()
.declareVariable("obj", Object.class)
.declareVariable("param", String.class)
.loadVariable("obj")
.invoke("undefinedMethod", Variable.get("param"), Variable.get("param2"))
.toJavaString();
fail("expected OutOfScopeException");
}
catch (OutOfScopeException oose) {
// expected
assertTrue(oose.getMessage().contains("param2"));
}
}
@Test
public void testInvokeUsingStandardizedLoadVariableReference() {
Context context = ContextBuilder.create()
.addVariable("s", String.class)
.getContext();
String s = StatementBuilder.create(context)
.load(Variable.get("s"))
.invoke("toUpperCase").toJavaString();
assertEquals("Failed using load() passing a variable reference", "s.toUpperCase()", s);
}
@Test
public void testInvokeUsingStandardizedLoadVariableInstance() {
Context context = ContextBuilder.create()
.addVariable("s", String.class)
.getContext();
Variable v = Variable.create("s", String.class);
String s = StatementBuilder.create(context)
.load(v)
.invoke("toUpperCase").toJavaString();
assertEquals("Failed using load() passing a variable instance", "s.toUpperCase()", s);
}
@Test
public void testInvokeUsingStandardizedLoadLiteral() {
String s = StatementBuilder.create()
.load("foo")
.invoke("toUpperCase").toJavaString();
assertEquals("Failed injecting literal with load()", "\"foo\".toUpperCase()", s);
}
@Test
public void testInvokeWithParameterTypeConversionOfIntegerToString() {
String s = StatementBuilder.create()
.declareVariable("str", String.class)
.loadVariable("str")
.invoke("endsWith", 123)
.toJavaString();
assertEquals("Failed to generate invocation with parameter type conversion", "str.endsWith(\"123\")", s);
}
@Test
public void testInvokeWithParameterTypeConversionOfStringToInteger() {
String s = StatementBuilder.create()
.declareVariable("str", String.class)
.loadVariable("str")
.invoke("substring", "1", "3")
.toJavaString();
assertEquals("Failed to generate invocation with parameter type conversion", "str.substring(1, 3)", s);
}
@Test
public void testInvokeWithParameterTypeConversionOfVariable() {
Context c = Context.create().addVariable("n", Integer.class, 123);
String s = StatementBuilder.create(c)
.declareVariable("str", String.class)
.loadVariable("str")
.invoke("endsWith", c.getVariable("n").getValue())
.toJavaString();
assertEquals("Failed to generate invocation with parameter type conversion of variable",
"str.endsWith(\"123\")", s);
}
@Test
public void testInvokeStaticMethod() {
String s = StatementBuilder.create()
.invokeStatic(Integer.class, "getInteger", "123")
.toJavaString();
assertEquals("Failed to generate static method invocation", "Integer.getInteger(\"123\")", s);
}
@Test
public void testInvokeUndefinedStaticMethod() {
try {
StatementBuilder.create()
.invokeStatic(Integer.class, "intValue")
.toJavaString();
fail("expected UndefinedMethodException");
}
catch (UndefinedMethodException udme) {
// expected
assertEquals("Wrong exception details", udme.getMethodName(), "intValue");
}
}
@Test
public void testInvokeWithVariableReturnType() {
String s =
StatementBuilder.create(Context.create().autoImport())
.declareVariable("s", String.class)
.declareVariable("str", String.class,
StatementBuilder.create().invokeStatic(Foo.class, "foo", Variable.get("s")))
.toJavaString();
assertEquals("Failed to generate method invocation using variable return type",
"String str = Foo.foo(s);", s);
}
@Test
public void testInvokeWithInvalidVariableReturnType() {
try {
StatementBuilder.create(Context.create().autoImport())
.declareVariable("list", new TypeLiteral<List<String>>() {
})
.declareVariable("n", Integer.class,
StatementBuilder.create().invokeStatic(Foo.class, "bar", Variable.get("list")))
.toJavaString();
fail("expected InvalidTypeException");
}
catch (InvalidTypeException e) {
// expected
assertEquals("Wrong exception message",
"java.lang.Integer is not assignable from java.lang.String", e.getMessage());
}
}
@Test
public void testInvokeWithParameterizedListAndVariableReturnType() {
String s =
StatementBuilder.create(Context.create().autoImport())
.declareVariable("list", new TypeLiteral<List<String>>() {
})
.declareVariable("str", String.class,
StatementBuilder.create().invokeStatic(Foo.class, "bar", Variable.get("list")))
.toJavaString();
assertEquals("Failed to generate method invocation with variable return type inferred from List<T>",
"String str = Foo.bar(list);", s);
}
@Test
public void testInvokeWithNestedParameterizedListAndVariableReturnType() {
String s =
StatementBuilder.create(Context.create().autoImport())
.declareVariable("n", int.class)
.declareVariable("list", new TypeLiteral<List<List<Map<String, Integer>>>>() {
})
.declareVariable("str", String.class,
StatementBuilder.create().invokeStatic(Foo.class, "bar", Variable.get("n"), Variable.get("list")))
.toJavaString();
assertEquals("Failed to generate method invocation with variable return type inferred from nested List<T>",
"String str = Foo.bar(n, list);", s);
}
@Test
public void testInvokeWithParameterizedMapAndVariableReturnType() {
String s =
StatementBuilder.create(Context.create().autoImport())
.declareVariable("map", new TypeLiteral<Map<String, Integer>>() {
})
.declareVariable("val", Integer.class,
StatementBuilder.create().invokeStatic(Foo.class, "bar", Variable.get("map")))
.toJavaString();
assertEquals("Failed to generate method invocation with variable return type inferred from Map<K, V>",
"Integer val = Foo.bar(map);", s);
}
@Test
public void testInvokeWithParameterizedClassAndVariableReturnType() {
String s =
StatementBuilder.create(Context.create().autoImport())
.declareVariable("set", Set.class,
StatementBuilder.create().invokeStatic(Foo.class, "baz", Set.class))
.toJavaString();
assertEquals("Failed to generate method invocation with variable return type inferred from Class<T>",
"Set set = Foo.baz(Set.class);", s);
}
@Test
public void testLookupOfMethodWithArrayParameters() {
final MetaClass metaClass = MetaClassFactory.get(Arrays.class);
final MetaMethod equals = metaClass.getBestMatchingMethod("equals", Class[].class, Class[].class);
assertEquals("public boolean equals([[Ljava.lang.Object;, [Ljava.lang.Object;])", equals.toString());
}
}