/* * Copyright (C) 2014 Google, Inc. * * 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 com.squareup.javapoet; import com.google.testing.compile.CompilationRule; import java.util.Map; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mockito; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Mockito.when; @RunWith(JUnit4.class) public final class ClassNameTest { @Rule public CompilationRule compilationRule = new CompilationRule(); @Test public void bestGuessForString_simpleClass() { assertThat(ClassName.bestGuess(String.class.getName())) .isEqualTo(ClassName.get("java.lang", "String")); } @Test public void bestGuessNonAscii() { ClassName className = ClassName.bestGuess( "com.\ud835\udc1andro\ud835\udc22d.\ud835\udc00ctiv\ud835\udc22ty"); assertEquals("com.\ud835\udc1andro\ud835\udc22d", className.packageName()); assertEquals("\ud835\udc00ctiv\ud835\udc22ty", className.simpleName()); } static class OuterClass { static class InnerClass {} } @Test public void bestGuessForString_nestedClass() { assertThat(ClassName.bestGuess(Map.Entry.class.getCanonicalName())) .isEqualTo(ClassName.get("java.util", "Map", "Entry")); assertThat(ClassName.bestGuess(OuterClass.InnerClass.class.getCanonicalName())) .isEqualTo(ClassName.get("com.squareup.javapoet", "ClassNameTest", "OuterClass", "InnerClass")); } @Test public void bestGuessForString_defaultPackage() { assertThat(ClassName.bestGuess("SomeClass")) .isEqualTo(ClassName.get("", "SomeClass")); assertThat(ClassName.bestGuess("SomeClass.Nested")) .isEqualTo(ClassName.get("", "SomeClass", "Nested")); assertThat(ClassName.bestGuess("SomeClass.Nested.EvenMore")) .isEqualTo(ClassName.get("", "SomeClass", "Nested", "EvenMore")); } @Test public void bestGuessForString_confusingInput() { assertBestGuessThrows(""); assertBestGuessThrows("."); assertBestGuessThrows(".Map"); assertBestGuessThrows("java"); assertBestGuessThrows("java.util"); assertBestGuessThrows("java.util."); assertBestGuessThrows("java..util.Map.Entry"); assertBestGuessThrows("java.util..Map.Entry"); assertBestGuessThrows("java.util.Map..Entry"); assertBestGuessThrows("com.test.$"); assertBestGuessThrows("com.test.LooksLikeAClass.pkg"); assertBestGuessThrows("!@#$gibberish%^&*"); } private void assertBestGuessThrows(String s) { try { ClassName.bestGuess(s); fail(); } catch (IllegalArgumentException expected) { } } @Test public void createNestedClass() { ClassName foo = ClassName.get("com.example", "Foo"); ClassName bar = foo.nestedClass("Bar"); assertThat(bar).isEqualTo(ClassName.get("com.example", "Foo", "Bar")); ClassName baz = bar.nestedClass("Baz"); assertThat(baz).isEqualTo(ClassName.get("com.example", "Foo", "Bar", "Baz")); } static class $Outer { static class $Inner {} } @Test public void classNameFromTypeElement() { Elements elements = compilationRule.getElements(); TypeElement object = elements.getTypeElement(Object.class.getCanonicalName()); assertThat(ClassName.get(object).toString()).isEqualTo("java.lang.Object"); TypeElement outer = elements.getTypeElement($Outer.class.getCanonicalName()); assertThat(ClassName.get(outer).toString()).isEqualTo("com.squareup.javapoet.ClassNameTest.$Outer"); TypeElement inner = elements.getTypeElement($Outer.$Inner.class.getCanonicalName()); assertThat(ClassName.get(inner).toString()).isEqualTo("com.squareup.javapoet.ClassNameTest.$Outer.$Inner"); } /** * Buck builds with "source-based ABI generation" and those builds don't support * {@link TypeElement#getKind()}. Test to confirm that we don't use that API. */ @Test public void classNameFromTypeElementDoesntUseGetKind() { Elements elements = compilationRule.getElements(); TypeElement object = elements.getTypeElement(Object.class.getCanonicalName()); assertThat(ClassName.get(preventGetKind(object)).toString()) .isEqualTo("java.lang.Object"); TypeElement outer = elements.getTypeElement($Outer.class.getCanonicalName()); assertThat(ClassName.get(preventGetKind(outer)).toString()) .isEqualTo("com.squareup.javapoet.ClassNameTest.$Outer"); TypeElement inner = elements.getTypeElement($Outer.$Inner.class.getCanonicalName()); assertThat(ClassName.get(preventGetKind(inner)).toString()) .isEqualTo("com.squareup.javapoet.ClassNameTest.$Outer.$Inner"); } /** Returns a new instance like {@code object} that throws on {@code getKind()}. */ private TypeElement preventGetKind(TypeElement object) { TypeElement spy = Mockito.spy(object); when(spy.getKind()).thenThrow(new AssertionError()); when(spy.getEnclosingElement()).thenAnswer(invocation -> { Object enclosingElement = invocation.callRealMethod(); return enclosingElement instanceof TypeElement ? preventGetKind((TypeElement) enclosingElement) : enclosingElement; }); return spy; } @Test public void classNameFromClass() { assertThat(ClassName.get(Object.class).toString()) .isEqualTo("java.lang.Object"); assertThat(ClassName.get(OuterClass.InnerClass.class).toString()) .isEqualTo("com.squareup.javapoet.ClassNameTest.OuterClass.InnerClass"); assertThat((ClassName.get(new Object() {}.getClass())).toString()) .isEqualTo("com.squareup.javapoet.ClassNameTest$1"); assertThat((ClassName.get(new Object() { Object inner = new Object() {}; }.inner.getClass())).toString()) .isEqualTo("com.squareup.javapoet.ClassNameTest$2$1"); assertThat((ClassName.get($Outer.class)).toString()) .isEqualTo("com.squareup.javapoet.ClassNameTest.$Outer"); assertThat((ClassName.get($Outer.$Inner.class)).toString()) .isEqualTo("com.squareup.javapoet.ClassNameTest.$Outer.$Inner"); } @Test public void peerClass() { assertThat(ClassName.get(Double.class).peerClass("Short")) .isEqualTo(ClassName.get(Short.class)); assertThat(ClassName.get("", "Double").peerClass("Short")) .isEqualTo(ClassName.get("", "Short")); assertThat(ClassName.get("a.b", "Combo", "Taco").peerClass("Burrito")) .isEqualTo(ClassName.get("a.b", "Combo", "Burrito")); } @Test public void fromClassRejectionTypes() { try { ClassName.get(int.class); fail(); } catch (IllegalArgumentException ignored) { } try { ClassName.get(void.class); fail(); } catch (IllegalArgumentException ignored) { } try { ClassName.get(Object[].class); fail(); } catch (IllegalArgumentException ignored) { } } @Test public void reflectionName() { assertEquals("java.lang.Object", TypeName.OBJECT.reflectionName()); assertEquals("java.lang.Thread$State", ClassName.get(Thread.State.class).reflectionName()); assertEquals("java.util.Map$Entry", ClassName.get(Map.Entry.class).reflectionName()); assertEquals("Foo", ClassName.get("", "Foo").reflectionName()); assertEquals("Foo$Bar$Baz", ClassName.get("", "Foo", "Bar", "Baz").reflectionName()); assertEquals("a.b.c.Foo$Bar$Baz", ClassName.get("a.b.c", "Foo", "Bar", "Baz").reflectionName()); } @Test public void canonicalName() { assertEquals("java.lang.Object", TypeName.OBJECT.canonicalName()); assertEquals("java.lang.Thread.State", ClassName.get(Thread.State.class).canonicalName()); assertEquals("java.util.Map.Entry", ClassName.get(Map.Entry.class).canonicalName()); assertEquals("Foo", ClassName.get("", "Foo").canonicalName()); assertEquals("Foo.Bar.Baz", ClassName.get("", "Foo", "Bar", "Baz").canonicalName()); assertEquals("a.b.c.Foo.Bar.Baz", ClassName.get("a.b.c", "Foo", "Bar", "Baz").canonicalName()); } }