/*
* 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.jboss.errai.codegen.test.ClassBuilderTestResult.*;
import static org.junit.Assert.fail;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.Map;
import org.jboss.errai.codegen.InnerClass;
import org.jboss.errai.codegen.Modifier;
import org.jboss.errai.codegen.Parameter;
import org.jboss.errai.codegen.Variable;
import org.jboss.errai.codegen.builder.ClassStructureBuilder;
import org.jboss.errai.codegen.builder.impl.ClassBuilder;
import org.jboss.errai.codegen.exception.UndefinedMethodException;
import org.jboss.errai.codegen.meta.MetaClassFactory;
import org.jboss.errai.codegen.test.model.Baz;
import org.jboss.errai.codegen.test.model.tree.Parent;
import org.jboss.errai.codegen.util.Stmt;
import org.junit.Test;
/**
* Tests the {@link ClassBuilder} API.
*
* @author Mike Brock <cbrock@redhat.com>
* @author Christian Sadilek <csadilek@redhat.com>
*/
public class ClassBuilderTest extends AbstractCodegenTest {
@Test
public void testDefineClassImplementingInterface() {
final String cls = ClassBuilder.define("org.foo.Bar")
.publicScope()
.implementsInterface(Serializable.class)
.body()
.privateField("name", String.class)
.finish()
.toJavaString();
System.out.println(cls);
assertEquals("failed to generate class definition implementing an interface", CLASS_IMPLEMENTING_INTERFACE, cls);
}
@Test
public void testDefineClassImplementingMultipleInterfaces() {
final String cls = ClassBuilder.define("org.foo.Bar")
.publicScope()
.implementsInterface(Serializable.class)
.implementsInterface(Cloneable.class)
.body()
.privateField("name", String.class)
.finish()
.toJavaString();
assertEquals("failed to generate class definition implementing multiple interfaces",
CLASS_IMPLEMENTING_MULTIPLE_INTERFACES, cls);
}
@Test
public void testDefineClassWithInnerClass() {
final ClassStructureBuilder<?> innerClass = ClassBuilder.define("Inner")
.publicScope().body();
final String cls = ClassBuilder.define("foo.bar.Baz")
.publicScope()
.body()
.declaresInnerClass(new InnerClass(innerClass.getClassDefinition()))
.toJavaString();
assertEquals("failed to generate class with method using inner class",
CLASS_DECLARING_INNER_CLASS, cls);
}
@Test
public void testDefineInnerClassInMethod() {
final ClassStructureBuilder<?> innerClass = ClassBuilder.define("Inner")
.packageScope()
.implementsInterface(Serializable.class)
.body()
.privateField("name", String.class)
.finish()
.publicMethod(void.class, "setName", Parameter.of(String.class, "name", true))
.append(Stmt.loadClassMember("name").assignValue(Variable.get("name")))
.finish();
final String cls = ClassBuilder.define("foo.bar.Baz")
.publicScope()
.body()
.publicMethod(void.class, "someMethod")
.append(new InnerClass(innerClass.getClassDefinition()))
.append(Stmt.newObject(innerClass.getClassDefinition()))
.finish()
.toJavaString();
assertEquals("failed to generate class with method using inner class",
CLASS_WITH_METHOD_USING_INNER_CLASS, cls);
}
@Test
public void testDefineClassWithAccessorMethods() {
final String cls = ClassBuilder.define("org.foo.Foo")
.publicScope()
.body()
.privateField("name", String.class)
.initializesWith(Stmt.load("default"))
.finish()
.publicMethod(String.class, "getName")
.append(Stmt.loadVariable("name").returnValue())
.finish()
.publicMethod(void.class, "setName", Parameter.of(String.class, "name"))
.append(Stmt.loadClassMember("name").assignValue(Variable.get("name")))
.finish()
.toJavaString();
assertEquals("failed to generate class definition with accessor methods", CLASS_WITH_ACCESSOR_METHODS, cls);
}
@Test
public void testDefineClassWithAccessorMethodsUsingThisKeyword() {
final String cls = ClassBuilder
.define("org.foo.Foo")
.publicScope()
.body()
.privateField("name", String.class)
.initializesWith(Stmt.load("default"))
.finish()
.publicMethod(String.class, "getName")
.append(Stmt.loadVariable("name").returnValue())
.finish()
.publicMethod(void.class, "setName", Parameter.of(String.class, "name"))
.append(Stmt.loadVariable("this.name").assignValue(Variable.get("name")))
.finish()
.toJavaString();
assertEquals("failed to generate class definition with accessor methods", CLASS_WITH_ACCESSOR_METHODS, cls);
}
@Test
public void testDefineClassWithParent() {
final String cls = ClassBuilder
.define("org.foo.Foo", String.class)
.publicScope()
.body()
.publicConstructor(Parameter.of(int.class, "i"))
.finish()
.toJavaString();
assertEquals("failed to generate class with parent", CLASS_WITH_PARENT, cls);
}
@Test
public void testDefineClassWithFieldInheritance() {
final String cls = ClassBuilder
.define("org.foo.Foo", Parent.class)
.publicScope()
.body()
.publicConstructor()
.append(Stmt.loadVariable("parentProtected").assignValue(0))
.append(Stmt.loadVariable("parentPublic").assignValue(0))
.finish()
.toJavaString();
assertEquals("failed to generate class with parent", CLASS_WITH_FIELD_INHERITANCE, cls);
}
@Test
public void testDefineAbstractClass() {
final String cls = ClassBuilder
.define("org.foo.Foo")
.publicScope()
.abstractClass()
.body()
.publicConstructor()
.finish()
.toJavaString();
assertEquals("failed to generate abstract class", ABSTRACT_CLASS, cls);
}
@Test
public void testDefineAbstractClassWithAbstractMethods() {
final String cls = ClassBuilder
.define("org.foo.Foo")
.publicScope()
.abstractClass()
.body()
.publicConstructor()
.finish()
.publicAbstractMethod(void.class, "foo")
.finish()
.protectedAbstractMethod(void.class, "bar")
.finish()
.publicMethod(void.class, "baz")
.finish()
.toJavaString();
assertEquals("failed to generate abstract class with abstract method", ABSTRACT_CLASS_WITH_ABSTRACT_METHODS, cls);
}
@SuppressWarnings("unchecked")
@Test
public void testDefineAbstractClassWithAbstractMethods2() {
final String cls = ClassBuilder
.define("org.foo.Foo")
.publicScope()
.abstractClass()
.body()
.publicConstructor()
.finish()
.publicAbstractMethod(MetaClassFactory.get(String.class), "someString").finish()
.publicAbstractMethod(Integer.class, "someInteger", Parameter.finalOf(long.class, "aLong")).finish()
.publicAbstractMethod(void.class, "foo", String.class, Integer.class).throws_(Throwable.class)
.protectedAbstractMethod(void.class, "bar", Long.class, Double.class).throws_(UnsupportedOperationException.class)
.protectedAbstractMethod(Long.class, "funTimes", Parameter.finalOf(String.class, "str")).finish()
.packageAbstractMethod(void.class, "foobaz", Map.class) .throws_(MetaClassFactory.get(ClassNotFoundException.class))
.packageAbstractMethod(Float.class, "boringTimes", Parameter.of(byte[].class, "byteArr")).finish()
.publicMethod(void.class, "baz")
.finish()
.toJavaString();
assertEquals(ABSTRACT_CLASS_WITH_ABSTRACT_METHODS_2, cls);
}
@Test
public void testDefineClassWithConstructorCallingSuper() {
final String cls = ClassBuilder.define("org.foo.Foo")
.publicScope()
.body()
.publicConstructor()
.callSuper()
.finish()
.toJavaString();
assertEquals("failed to generate class with constructor calling super()",
CLASS_WITH_CONSTRUCTOR_CALLING_SUPER, cls);
}
@Test
public void testDefineClassWithConstructorCallingThis() {
final String cls = ClassBuilder.define("org.foo.Foo")
.publicScope()
.body()
.privateField("b", boolean.class)
.finish()
.publicConstructor()
.callThis(false)
.finish()
.publicConstructor(Parameter.of(boolean.class, "b"))
.append(Stmt.loadClassMember("b").assignValue(Variable.get("b")))
.finish()
.toJavaString();
assertEquals("failed to generate class with constructor calling this()",
CLASS_WITH_CONSTRUCTOR_CALLING_THIS, cls);
}
@Test
public void testDefineClassWithMethodCallingMethodOnThis() {
final String cls = ClassBuilder.define("org.foo.Foo")
.publicScope()
.body()
.publicMethod(void.class, "bar")
.append(Stmt.loadVariable("this").invoke("foo"))
.finish()
.publicMethod(String.class, "foo")
.append(Stmt.load(null).returnValue())
.finish()
.toJavaString();
assertEquals("failed to generate class with method calling method on this",
CLASS_WITH_METHOD_CALLING_METHOD_ON_THIS, cls);
}
@Test
public void testDefineClassWithMethodCallingInvalidMethodOnThis() {
try {
ClassBuilder.define("org.foo.Foo")
.publicScope()
.body()
.publicMethod(void.class, "bar")
.append(Stmt.loadVariable("this").invoke("foo", "invalidParam"))
.finish()
.publicMethod(String.class, "foo")
.append(Stmt.load(null).returnValue())
.finish()
.toJavaString();
fail("exprected UndefinedMethodException");
}
catch (UndefinedMethodException udme) {
// expected
assertEquals("Wrong exception thrown", udme.getMethodName(), "foo");
}
}
@Test
public void testDefineClassWithMethodCallingMethodOnSuper() {
final String cls = ClassBuilder.define("org.foo.Foo")
.publicScope()
.body()
.publicMethod(void.class, "bar")
.append(Stmt.loadVariable("this").invoke("foo"))
.finish()
.publicMethod(String.class, "foo")
.append(Stmt.loadVariable("super").invoke("toString").returnValue())
.finish()
.toJavaString();
assertEquals("failed to generate class with method calling method on this",
CLASS_WITH_METHOD_CALLING_METHOD_ON_SUPER, cls);
}
@Test
public void testDefineClassWithMethodCallingInvalidMethodOnSuper() {
try {
ClassBuilder.define("org.foo.Foo")
.publicScope()
.body()
.publicMethod(void.class, "bar")
.append(Stmt.loadVariable("this").invoke("foo"))
.finish()
.publicMethod(String.class, "foo")
.append(Stmt.loadVariable("super").invoke("undefinedMethod"))
.finish()
.toJavaString();
fail("exprected UndefinedMethodException");
}
catch (UndefinedMethodException udme) {
// expected
assertEquals("Wrong exception thrown", udme.getMethodName(), "undefinedMethod");
}
}
@Test
public void testDefineClassWithMethodHavingThrowsDeclaration() {
@SuppressWarnings("unchecked")
final String cls = ClassBuilder
.define("org.foo.Foo")
.publicScope()
.body()
.publicMethod(void.class, "initialize")
.throws_(Exception.class, IllegalArgumentException.class)
.finish()
.toJavaString();
assertEquals("failed to generate class with method having throws declaration",
CLASS_WITH_METHOD_HAVING_THROWS_DECLARATION, cls);
}
@Test
public void testDefineClassWithMethodsOfAllScopes() {
final String cls = ClassBuilder
.define("org.foo.Foo")
.publicScope()
.body()
.publicMethod(void.class, "publicMethod")
.finish()
.protectedMethod(void.class, "protectedMethod")
.finish()
.packageMethod(void.class, "packagePrivateMethod")
.finish()
.privateMethod(void.class, "privateMethod")
.finish()
.toJavaString();
assertEquals("failed to generate class with methods of all scopes", CLASS_WITH_METHODS_OF_ALL_SCOPES, cls);
}
@Test
public void testDefineClassWithFieldsOfAllScopes() {
final String cls = ClassBuilder
.define("org.foo.Foo")
.publicScope()
.body()
.publicField("publicField", int.class)
.finish()
.protectedField("protectedField", int.class)
.finish()
.packageField("packagePrivateField", int.class)
.finish()
.privateField("privateField", int.class)
.finish()
.toJavaString();
assertEquals("failed to generate class with fields of all scopes", CLASS_WITH_FIELDS_OF_ALL_SCOPES, cls);
}
@Test
public void testDefineClassWithConstructorsOfAllScopes() {
final String cls = ClassBuilder
.define("org.foo.Foo")
.publicScope()
.body()
.publicConstructor()
.finish()
.protectedConstructor()
.finish()
.packageConstructor()
.finish()
.privateConstructor()
.finish()
.toJavaString();
assertEquals("failed to generate class with constructors of all scopes",
CLASS_WITH_CONSTRUCTORS_OF_ALL_SCOPES, cls);
}
@Test
public void testDefineClassByImplementingInterface() {
final String cls = ClassBuilder.implement(Baz.class)
.publicMethod(void.class, "someMethod")
.finish().toJavaString();
assertEquals("failed to generate class by implementing an interface",
CLASS_DEFINITION_BY_IMPLEMENTING_INTERFACE, cls);
}
@Test
public void testDefineClassWithStaticMethod() {
final String cls = ClassBuilder.define("my.test.Clazz")
.publicScope().body()
.publicMethod(void.class, "test").modifiers(Modifier.Static)
.body()
.append(Stmt.loadStatic(System.class, "out").invoke("println", "Hello, World!"))
.finish()
.toJavaString();
assertEquals("failed to generate class with static method", CLASS_WITH_STATIC_METHOD, cls);
}
@Test
public void testDefineClassWithJSNIMethod() {
final String cls = ClassBuilder.define("my.test.Clazz")
.publicScope().body()
.publicMethod(void.class, "test").modifiers(Modifier.JSNI)
.body()
.append(Stmt.loadStatic(System.class, "out").invoke("println", "Hello, World!"))
.finish()
.toJavaString();
assertEquals("failed to generate class with JSNI method", CLASS_WITH_JSNI_METHOD, cls);
}
public interface TestInterface {
}
@Test
public void testCollidingImportsWithInnerClass() {
final String cls = ClassBuilder.define("my.test.Clazz")
.publicScope()
.implementsInterface(org.jboss.errai.codegen.test.model.TestInterface.class)
.implementsInterface(TestInterface.class)
.implementsInterface(Serializable.class)
.body()
.privateField("name", String.class)
.finish()
.toJavaString();
assertEquals("failed to generate class with colliding imports",
CLASS_WITH_COLLIDING_IMPORTS_WITH_INNER_CLASS, cls);
}
@Test
public void testCollidingImportsWithInnerClassFirst() {
final String cls = ClassBuilder.define("my.test.Clazz")
.publicScope()
.implementsInterface(TestInterface.class)
.implementsInterface(org.jboss.errai.codegen.test.model.TestInterface.class)
.implementsInterface(Serializable.class)
.body()
.privateField("name", String.class)
.finish()
.toJavaString();
assertEquals("failed to generate class with colliding imports",
CLASS_WITH_COLLIDING_IMPORTS_WITH_INNER_CLASS_FIRST, cls);
}
@Test
public void testCollidingImportsWithJavaLang() {
final String cls = ClassBuilder.define("my.test.Clazz")
.publicScope()
.body()
.privateField("i", org.jboss.errai.codegen.test.model.Integer.class)
.finish()
.privateField("j", Integer.class)
.finish()
.toJavaString();
assertEquals("failed to generate class with colliding imports",
CLASS_WITH_COLLIDING_IMPORTS_WITH_JAVA_LANG, cls);
}
@Test
public void testCollidingImportsWithJavaLangFirst() {
final String cls = ClassBuilder.define("my.test.Clazz")
.publicScope()
.body()
.privateField("i", Integer.class)
.finish()
.privateField("j", org.jboss.errai.codegen.test.model.Integer.class)
.finish()
.toJavaString();
assertEquals("failed to generate class with colliding imports",
CLASS_WITH_COLLIDING_IMPORTS_WITH_JAVA_LANG_FIRST, cls);
}
@Test
public void testThisReferenceWithStmtLoadVariable() {
final ClassStructureBuilder<? extends ClassStructureBuilder<?>> body =
ClassBuilder.define("org.foo.Foo").publicScope().body();
final String cls = body
.publicMethod(body.getClassDefinition(), "getThis")
.append(Stmt.loadVariable("this").returnValue())
.finish()
.toJavaString();
assertEquals("did not properly render 'this' reference", "package org.foo;\n" +
"\n" +
"\n" +
"public class Foo {\n" +
" public Foo getThis() {\n" +
" return this;\n" +
" }\n" +
"}", cls);
}
@Test
public void testMethodAnnotated() {
final String cls = ClassBuilder.define("MyRunnable")
.publicScope().implementsInterface(Runnable.class)
.body()
.publicMethod(void.class, "run")
.annotatedWith(new SuppressWarnings() {
@Override
public String[] value() {
return new String[]{"blah"};
}
@Override
public Class<? extends Annotation> annotationType() {
return SuppressWarnings.class;
}
}).body()
.append(Stmt.returnVoid())
.finish().toJavaString();
assertEquals("public class MyRunnable implements Runnable {\n" +
" @SuppressWarnings(\"blah\") public void run() {\n" +
" return;\n" +
" }\n" +
"}", cls);
}
@Test
public void testClassComment() throws Exception {
final String cls = ClassBuilder.define("org.foo.Bar")
.classComment("A foo-ish bar")
.publicScope()
.body()
.toJavaString();
assertEquals(CLASS_WITH_CLASS_COMMENT, cls);
}
}