/*
* Copyright 2015 Google Inc. All rights reserved.
*
* 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.inferred.freebuilder.processor.util;
import static com.google.common.truth.Truth.assertThat;
import static org.inferred.freebuilder.processor.util.ClassTypeImpl.newTopLevelClass;
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeAsTypeElement;
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeDeclared;
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeVariable;
import static org.inferred.freebuilder.processor.util.feature.SourceLevel.JAVA_7;
import com.google.common.base.Function;
import org.inferred.freebuilder.processor.util.testing.ModelRule;
import org.junit.Rule;
import org.junit.Test;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeVariable;
public class GenericElementTest {
private static final QualifiedName FOO_BAR_NAME = QualifiedName.of("org.example", "FooBar");
@Rule public final ModelRule model = new ModelRule();
@Test
public void testNonGenericElement() {
GenericElement foobar =
new GenericElement.Builder(FOO_BAR_NAME).build();
assertThat(foobar.getSimpleName().toString()).isEqualTo("FooBar");
assertThat(foobar.getTypeParameters()).isEmpty();
assertThat(SourceStringBuilder.simple().add("%s", foobar).toString()).isEqualTo("FooBar");
}
@Test
public void testGenericElement() {
GenericElement foobar = new GenericElement.Builder(FOO_BAR_NAME)
.addTypeParameter("T")
.addTypeParameter("C")
.build();
assertThat(foobar.getSimpleName().toString()).isEqualTo("FooBar");
assertThat(foobar.getTypeParameters()).hasSize(2);
assertThat(foobar.getTypeParameters().get(0).getSimpleName().toString()).isEqualTo("T");
assertThat(foobar.getTypeParameters().get(0).toString()).isEqualTo("T");
assertThat(foobar.getTypeParameters().get(1).getSimpleName().toString()).isEqualTo("C");
assertThat(foobar.getTypeParameters().get(1).toString()).isEqualTo("C");
}
@Test
public void testBoundedGenericElement() {
Function<TypeElement, Void> test = new Function<TypeElement, Void>() {
@Override
public Void apply(TypeElement foobar) {
assertThat(foobar.getSimpleName().toString()).isEqualTo("FooBar");
assertThat(foobar.getTypeParameters()).hasSize(2);
assertThat(foobar.getTypeParameters().get(0).getSimpleName().toString()).isEqualTo("T");
assertThat(foobar.getTypeParameters().get(0).toString()).isEqualTo("T");
assertThat(foobar.getTypeParameters().get(1).getSimpleName().toString()).isEqualTo("C");
assertThat(foobar.getTypeParameters().get(1).toString()).isEqualTo("C");
return null;
}
};
TypeElement realFoobar =
model.newType("package org.example; interface FooBar<T extends Number, C> { }");
GenericElement fakeFoobar = new GenericElement.Builder(FOO_BAR_NAME)
.addTypeParameter("T", newTopLevelClass("java.lang.Number"))
.addTypeParameter("C")
.build();
test.apply(realFoobar);
test.apply(fakeFoobar);
}
@Test
public void testGenericMirror_withTypeVariables() {
Function<DeclaredType, Void> test = new Function<DeclaredType, Void>() {
@Override public Void apply(DeclaredType foobar) {
assertThat(foobar.asElement().getSimpleName().toString()).isEqualTo("FooBar");
assertThat(foobar.getTypeArguments()).hasSize(2);
assertThat(SourceStringBuilder.simple(JAVA_7).add("%s", foobar).toString())
.isEqualTo("FooBar<T, C>");
return null;
}
};
DeclaredType realFoobar = (DeclaredType)
model.newType("package org.example; interface FooBar<T, C> { }").asType();
GenericMirror fakeFoobar = new GenericElement.Builder(FOO_BAR_NAME)
.addTypeParameter("T")
.addTypeParameter("C")
.build()
.asType();
test.apply(realFoobar);
test.apply(fakeFoobar);
}
@Test
public void testGenericMirror_withBounds() {
Function<DeclaredType, Void> test = new Function<DeclaredType, Void>() {
@Override public Void apply(DeclaredType foobar) {
assertThat(foobar.asElement().getSimpleName().toString()).isEqualTo("FooBar");
assertThat(foobar.getTypeArguments()).hasSize(2);
assertThat(SourceStringBuilder.simple(JAVA_7).add("%s", foobar).toString())
.isEqualTo("FooBar<T, C>");
return null;
}
};
DeclaredType realFoobar = (DeclaredType)
model.newType("package org.example; interface FooBar<T extends Number, C> { }").asType();
GenericMirror fakeFoobar = new GenericElement.Builder(FOO_BAR_NAME)
.addTypeParameter("T", newTopLevelClass("java.lang.Number"))
.addTypeParameter("C")
.build()
.asType();
test.apply(realFoobar);
test.apply(fakeFoobar);
}
@Test
public void testGenericMirror_withSelfReference() {
Function<DeclaredType, Void> test = new Function<DeclaredType, Void>() {
@Override public Void apply(DeclaredType foobar) {
// FooBar<E extends FooBar<E>>
TypeElement foobarElement = maybeAsTypeElement(foobar).get();
assertThat(foobarElement.getSimpleName().toString()).isEqualTo("FooBar");
assertThat(foobar.getTypeArguments()).hasSize(1);
assertThat(SourceStringBuilder.simple(JAVA_7).add("%s", foobar).toString())
.isEqualTo("FooBar<E>");
// E extends FooBar<E>
TypeParameterElement typeParameter = foobarElement.getTypeParameters().get(0);
assertThat(typeParameter.getSimpleName().toString()).isEqualTo("E");
assertThat(typeParameter.getBounds()).hasSize(1);
// FooBar<E>
DeclaredType bound = maybeDeclared(typeParameter.getBounds().get(0)).get();
assertThat(bound.asElement().getSimpleName().toString()).isEqualTo("FooBar");
assertThat(bound.getTypeArguments()).hasSize(1);
// E
TypeVariable typeArgument = maybeVariable(bound.getTypeArguments().get(0)).get();
assertThat(typeArgument.asElement()).isEqualTo(typeParameter);
return null;
}
};
DeclaredType realFoobar = (DeclaredType) model
.newType("package org.example; interface FooBar<E extends FooBar<E>> { }").asType();
GenericElement.Builder fakeFoobarBuilder = new GenericElement.Builder(FOO_BAR_NAME);
fakeFoobarBuilder.getTypeParameter("E").addBound(fakeFoobarBuilder.asType());
GenericMirror fakeFoobar = fakeFoobarBuilder.build().asType();
test.apply(realFoobar);
test.apply(fakeFoobar);
}
}