diff options
Diffstat (limited to 'src/test/java')
13 files changed, 913 insertions, 16 deletions
diff --git a/src/test/java/ClassNameNoPackageTest.java b/src/test/java/ClassNameNoPackageTest.java new file mode 100644 index 0000000..8b8545d --- /dev/null +++ b/src/test/java/ClassNameNoPackageTest.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 Square, 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. + */ + +import static com.google.common.truth.Truth.assertThat; + +import com.squareup.javapoet.ClassName; +import org.junit.Test; + +/** + * Since it is impossible to import classes from the default package into other + * modules, this test must live in this package. + */ +public final class ClassNameNoPackageTest { + @Test public void shouldSupportClassInDefaultPackage() { + ClassName className = ClassName.get(ClassNameNoPackageTest.class); + assertThat(className.packageName()).isEqualTo(""); + assertThat(className.simpleName()).isEqualTo("ClassNameNoPackageTest"); + assertThat(className.toString()).isEqualTo("ClassNameNoPackageTest"); + } +} diff --git a/src/test/java/com/squareup/javapoet/AnnotationSpecTest.java b/src/test/java/com/squareup/javapoet/AnnotationSpecTest.java index 49606c7..97c1e6e 100644 --- a/src/test/java/com/squareup/javapoet/AnnotationSpecTest.java +++ b/src/test/java/com/squareup/javapoet/AnnotationSpecTest.java @@ -20,6 +20,8 @@ import java.lang.annotation.Annotation; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; + import javax.lang.model.element.TypeElement; import org.junit.Rule; import org.junit.Test; @@ -371,6 +373,16 @@ public final class AnnotationSpecTest { } } + @Test public void modifyMembers() { + AnnotationSpec.Builder builder = AnnotationSpec.builder(SuppressWarnings.class) + .addMember("value", "$S", "Foo"); + + builder.members.clear(); + builder.members.put("value", Arrays.asList(CodeBlock.of("$S", "Bar"))); + + assertThat(builder.build().toString()).isEqualTo("@java.lang.SuppressWarnings(\"Bar\")"); + } + private String toString(TypeSpec typeSpec) { return JavaFile.builder("com.squareup.tacos", typeSpec).build().toString(); } diff --git a/src/test/java/com/squareup/javapoet/ClassNameTest.java b/src/test/java/com/squareup/javapoet/ClassNameTest.java index e2cc55e..590ad5d 100644 --- a/src/test/java/com/squareup/javapoet/ClassNameTest.java +++ b/src/test/java/com/squareup/javapoet/ClassNameTest.java @@ -193,4 +193,14 @@ public final class ClassNameTest { 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()); + } } diff --git a/src/test/java/com/squareup/javapoet/CodeBlockTest.java b/src/test/java/com/squareup/javapoet/CodeBlockTest.java index 2862809..11b75fa 100644 --- a/src/test/java/com/squareup/javapoet/CodeBlockTest.java +++ b/src/test/java/com/squareup/javapoet/CodeBlockTest.java @@ -339,4 +339,13 @@ public final class CodeBlockTest { CodeBlock joined = codeBlocks.stream().collect(CodeBlock.joining(" || ", "start {", "} end")); assertThat(joined.toString()).isEqualTo("start {\"hello\" || world.World || need tacos} end"); } + + @Test public void clear() { + CodeBlock block = CodeBlock.builder() + .addStatement("$S", "Test string") + .clear() + .build(); + + assertThat(block.toString()).isEmpty(); + } } diff --git a/src/test/java/com/squareup/javapoet/CodeWriterTest.java b/src/test/java/com/squareup/javapoet/CodeWriterTest.java new file mode 100644 index 0000000..331d000 --- /dev/null +++ b/src/test/java/com/squareup/javapoet/CodeWriterTest.java @@ -0,0 +1,23 @@ +package com.squareup.javapoet; + +import org.junit.Test; + +import java.io.IOException; + +import static com.google.common.truth.Truth.assertThat; + +public class CodeWriterTest { + + @Test + public void emptyLineInJavaDocDosEndings() throws IOException { + CodeBlock javadocCodeBlock = CodeBlock.of("A\r\n\r\nB\r\n"); + StringBuilder out = new StringBuilder(); + new CodeWriter(out).emitJavadoc(javadocCodeBlock); + assertThat(out.toString()).isEqualTo( + "/**\n" + + " * A\n" + + " *\n" + + " * B\n" + + " */\n"); + } +}
\ No newline at end of file diff --git a/src/test/java/com/squareup/javapoet/FieldSpecTest.java b/src/test/java/com/squareup/javapoet/FieldSpecTest.java index 63f7aa8..bc68f6f 100644 --- a/src/test/java/com/squareup/javapoet/FieldSpecTest.java +++ b/src/test/java/com/squareup/javapoet/FieldSpecTest.java @@ -28,10 +28,12 @@ public class FieldSpecTest { FieldSpec b = FieldSpec.builder(int.class, "foo").build(); assertThat(a.equals(b)).isTrue(); assertThat(a.hashCode()).isEqualTo(b.hashCode()); + assertThat(a.toString()).isEqualTo(b.toString()); a = FieldSpec.builder(int.class, "FOO", Modifier.PUBLIC, Modifier.STATIC).build(); b = FieldSpec.builder(int.class, "FOO", Modifier.PUBLIC, Modifier.STATIC).build(); assertThat(a.equals(b)).isTrue(); assertThat(a.hashCode()).isEqualTo(b.hashCode()); + assertThat(a.toString()).isEqualTo(b.toString()); } @Test public void nullAnnotationsAddition() { @@ -44,4 +46,21 @@ public class FieldSpecTest { .isEqualTo("annotationSpecs == null"); } } -}
\ No newline at end of file + + @Test public void modifyAnnotations() { + FieldSpec.Builder builder = FieldSpec.builder(int.class, "foo") + .addAnnotation(Override.class) + .addAnnotation(SuppressWarnings.class); + + builder.annotations.remove(1); + assertThat(builder.build().annotations).hasSize(1); + } + + @Test public void modifyModifiers() { + FieldSpec.Builder builder = FieldSpec.builder(int.class, "foo") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC); + + builder.modifiers.remove(1); + assertThat(builder.build().modifiers).containsExactly(Modifier.PUBLIC); + } +} diff --git a/src/test/java/com/squareup/javapoet/FileWritingTest.java b/src/test/java/com/squareup/javapoet/FileWritingTest.java index f817ddb..58e5b62 100644 --- a/src/test/java/com/squareup/javapoet/FileWritingTest.java +++ b/src/test/java/com/squareup/javapoet/FileWritingTest.java @@ -216,4 +216,11 @@ public final class FileWritingTest { + "class Taco {\n" + "}\n"); } + + @Test public void writeToPathReturnsPath() throws IOException { + JavaFile javaFile = JavaFile.builder("foo", TypeSpec.classBuilder("Taco").build()).build(); + Path filePath = javaFile.writeToPath(fsRoot); + // Cast to avoid ambiguity between assertThat(Path) and assertThat(Iterable<?>) + assertThat((Iterable<?>) filePath).isEqualTo(fsRoot.resolve(fs.getPath("foo", "Taco.java"))); + } } diff --git a/src/test/java/com/squareup/javapoet/JavaFileTest.java b/src/test/java/com/squareup/javapoet/JavaFileTest.java index e056116..e75a019 100644 --- a/src/test/java/com/squareup/javapoet/JavaFileTest.java +++ b/src/test/java/com/squareup/javapoet/JavaFileTest.java @@ -15,12 +15,19 @@ */ package com.squareup.javapoet; +import java.io.File; +import com.google.testing.compile.CompilationRule; import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -29,6 +36,13 @@ import static com.google.common.truth.Truth.assertThat; @RunWith(JUnit4.class) public final class JavaFileTest { + + @Rule public final CompilationRule compilation = new CompilationRule(); + + private TypeElement getElement(Class<?> clazz) { + return compilation.getElements().getTypeElement(clazz.getCanonicalName()); + } + @Test public void importStaticReadmeExample() { ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard"); ClassName namedBoards = ClassName.get("com.mattel", "Hoverboard", "Boards"); @@ -689,4 +703,312 @@ public final class JavaFileTest { + " A a;\n" + "}\n"); } + + @Test public void modifyStaticImports() throws Exception { + JavaFile.Builder builder = JavaFile.builder("com.squareup.tacos", + TypeSpec.classBuilder("Taco") + .build()) + .addStaticImport(File.class, "separator"); + + builder.staticImports.clear(); + builder.staticImports.add(File.class.getCanonicalName() + ".separatorChar"); + + String source = builder.build().toString(); + + assertThat(source).isEqualTo("" + + "package com.squareup.tacos;\n" + + "\n" + + "import static java.io.File.separatorChar;\n" + + "\n" + + "class Taco {\n" + + "}\n"); + } + + @Test public void alwaysQualifySimple() { + String source = JavaFile.builder("com.squareup.tacos", + TypeSpec.classBuilder("Taco") + .addField(Thread.class, "thread") + .alwaysQualify("Thread") + .build()) + .build() + .toString(); + assertThat(source).isEqualTo("" + + "package com.squareup.tacos;\n" + + "\n" + + "class Taco {\n" + + " java.lang.Thread thread;\n" + + "}\n"); + } + + @Test public void alwaysQualifySupersedesJavaLangImports() { + String source = JavaFile.builder("com.squareup.tacos", + TypeSpec.classBuilder("Taco") + .addField(Thread.class, "thread") + .alwaysQualify("Thread") + .build()) + .skipJavaLangImports(true) + .build() + .toString(); + assertThat(source).isEqualTo("" + + "package com.squareup.tacos;\n" + + "\n" + + "class Taco {\n" + + " java.lang.Thread thread;\n" + + "}\n"); + } + + @Test public void avoidClashesWithNestedClasses_viaClass() { + String source = JavaFile.builder("com.squareup.tacos", + TypeSpec.classBuilder("Taco") + // These two should get qualified + .addField(ClassName.get("other", "NestedTypeA"), "nestedA") + .addField(ClassName.get("other", "NestedTypeB"), "nestedB") + // This one shouldn't since it's not a nested type of Foo + .addField(ClassName.get("other", "NestedTypeC"), "nestedC") + // This one shouldn't since we only look at nested types + .addField(ClassName.get("other", "Foo"), "foo") + .avoidClashesWithNestedClasses(Foo.class) + .build()) + .build() + .toString(); + assertThat(source).isEqualTo("" + + "package com.squareup.tacos;\n" + + "\n" + + "import other.Foo;\n" + + "import other.NestedTypeC;\n" + + "\n" + + "class Taco {\n" + + " other.NestedTypeA nestedA;\n" + + "\n" + + " other.NestedTypeB nestedB;\n" + + "\n" + + " NestedTypeC nestedC;\n" + + "\n" + + " Foo foo;\n" + + "}\n"); + } + + @Test public void avoidClashesWithNestedClasses_viaTypeElement() { + String source = JavaFile.builder("com.squareup.tacos", + TypeSpec.classBuilder("Taco") + // These two should get qualified + .addField(ClassName.get("other", "NestedTypeA"), "nestedA") + .addField(ClassName.get("other", "NestedTypeB"), "nestedB") + // This one shouldn't since it's not a nested type of Foo + .addField(ClassName.get("other", "NestedTypeC"), "nestedC") + // This one shouldn't since we only look at nested types + .addField(ClassName.get("other", "Foo"), "foo") + .avoidClashesWithNestedClasses(getElement(Foo.class)) + .build()) + .build() + .toString(); + assertThat(source).isEqualTo("" + + "package com.squareup.tacos;\n" + + "\n" + + "import other.Foo;\n" + + "import other.NestedTypeC;\n" + + "\n" + + "class Taco {\n" + + " other.NestedTypeA nestedA;\n" + + "\n" + + " other.NestedTypeB nestedB;\n" + + "\n" + + " NestedTypeC nestedC;\n" + + "\n" + + " Foo foo;\n" + + "}\n"); + } + + @Test public void avoidClashesWithNestedClasses_viaSuperinterfaceType() { + String source = JavaFile.builder("com.squareup.tacos", + TypeSpec.classBuilder("Taco") + // These two should get qualified + .addField(ClassName.get("other", "NestedTypeA"), "nestedA") + .addField(ClassName.get("other", "NestedTypeB"), "nestedB") + // This one shouldn't since it's not a nested type of Foo + .addField(ClassName.get("other", "NestedTypeC"), "nestedC") + // This one shouldn't since we only look at nested types + .addField(ClassName.get("other", "Foo"), "foo") + .addType(TypeSpec.classBuilder("NestedTypeA").build()) + .addType(TypeSpec.classBuilder("NestedTypeB").build()) + .addSuperinterface(FooInterface.class) + .build()) + .build() + .toString(); + assertThat(source).isEqualTo("package com.squareup.tacos;\n" + + "\n" + + "import com.squareup.javapoet.JavaFileTest;\n" + + "import other.Foo;\n" + + "import other.NestedTypeC;\n" + + "\n" + + "class Taco implements JavaFileTest.FooInterface {\n" + + " other.NestedTypeA nestedA;\n" + + "\n" + + " other.NestedTypeB nestedB;\n" + + "\n" + + " NestedTypeC nestedC;\n" + + "\n" + + " Foo foo;\n" + + "\n" + + " class NestedTypeA {\n" + + " }\n" + + "\n" + + " class NestedTypeB {\n" + + " }\n" + + "}\n"); + } + + static class Foo { + static class NestedTypeA { + + } + static class NestedTypeB { + + } + } + + interface FooInterface { + class NestedTypeA { + + } + class NestedTypeB { + + } + } + + private TypeSpec.Builder childTypeBuilder() { + return TypeSpec.classBuilder("Child") + .addMethod(MethodSpec.methodBuilder("optionalString") + .returns(ParameterizedTypeName.get(Optional.class, String.class)) + .addStatement("return $T.empty()", Optional.class) + .build()) + .addMethod(MethodSpec.methodBuilder("pattern") + .returns(Pattern.class) + .addStatement("return null") + .build()); + } + + @Test + public void avoidClashes_parentChild_superclass_type() { + String source = JavaFile.builder("com.squareup.javapoet", + childTypeBuilder().superclass(Parent.class).build()) + .build() + .toString(); + assertThat(source).isEqualTo("package com.squareup.javapoet;\n" + + "\n" + + "import java.lang.String;\n" + + "\n" + + "class Child extends JavaFileTest.Parent {\n" + + " java.util.Optional<String> optionalString() {\n" + + " return java.util.Optional.empty();\n" + + " }\n" + + "\n" + + " java.util.regex.Pattern pattern() {\n" + + " return null;\n" + + " }\n" + + "}\n"); + } + + @Test + public void avoidClashes_parentChild_superclass_typeMirror() { + String source = JavaFile.builder("com.squareup.javapoet", + childTypeBuilder().superclass(getElement(Parent.class).asType()).build()) + .build() + .toString(); + assertThat(source).isEqualTo("package com.squareup.javapoet;\n" + + "\n" + + "import java.lang.String;\n" + + "\n" + + "class Child extends JavaFileTest.Parent {\n" + + " java.util.Optional<String> optionalString() {\n" + + " return java.util.Optional.empty();\n" + + " }\n" + + "\n" + + " java.util.regex.Pattern pattern() {\n" + + " return null;\n" + + " }\n" + + "}\n"); + } + + @Test + public void avoidClashes_parentChild_superinterface_type() { + String source = JavaFile.builder("com.squareup.javapoet", + childTypeBuilder().addSuperinterface(ParentInterface.class).build()) + .build() + .toString(); + assertThat(source).isEqualTo("package com.squareup.javapoet;\n" + + "\n" + + "import java.lang.String;\n" + + "import java.util.regex.Pattern;\n" + + "\n" + + "class Child implements JavaFileTest.ParentInterface {\n" + + " java.util.Optional<String> optionalString() {\n" + + " return java.util.Optional.empty();\n" + + " }\n" + + "\n" + + " Pattern pattern() {\n" + + " return null;\n" + + " }\n" + + "}\n"); + } + + @Test + public void avoidClashes_parentChild_superinterface_typeMirror() { + String source = JavaFile.builder("com.squareup.javapoet", + childTypeBuilder().addSuperinterface(getElement(ParentInterface.class).asType()).build()) + .build() + .toString(); + assertThat(source).isEqualTo("package com.squareup.javapoet;\n" + + "\n" + + "import java.lang.String;\n" + + "import java.util.regex.Pattern;\n" + + "\n" + + "class Child implements JavaFileTest.ParentInterface {\n" + + " java.util.Optional<String> optionalString() {\n" + + " return java.util.Optional.empty();\n" + + " }\n" + + "\n" + + " Pattern pattern() {\n" + + " return null;\n" + + " }\n" + + "}\n"); + } + + // Regression test for https://github.com/square/javapoet/issues/77 + // This covers class and inheritance + static class Parent implements ParentInterface { + static class Pattern { + + } + } + + interface ParentInterface { + class Optional { + + } + } + + // Regression test for case raised here: https://github.com/square/javapoet/issues/77#issuecomment-519972404 + @Test + public void avoidClashes_mapEntry() { + String source = JavaFile.builder("com.squareup.javapoet", + TypeSpec.classBuilder("MapType") + .addMethod(MethodSpec.methodBuilder("optionalString") + .returns(ClassName.get("com.foo", "Entry")) + .addStatement("return null") + .build()) + .addSuperinterface(Map.class) + .build()) + .build() + .toString(); + assertThat(source).isEqualTo("package com.squareup.javapoet;\n" + + "\n" + + "import java.util.Map;\n" + + "\n" + + "class MapType implements Map {\n" + + " com.foo.Entry optionalString() {\n" + + " return null;\n" + + " }\n" + + "}\n"); + } } diff --git a/src/test/java/com/squareup/javapoet/MethodSpecTest.java b/src/test/java/com/squareup/javapoet/MethodSpecTest.java index 5dfabaa..b768351 100644 --- a/src/test/java/com/squareup/javapoet/MethodSpecTest.java +++ b/src/test/java/com/squareup/javapoet/MethodSpecTest.java @@ -21,8 +21,9 @@ import java.io.IOException; import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.util.Arrays; -import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; import javax.lang.model.element.ExecutableElement; @@ -37,6 +38,8 @@ import org.junit.Test; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; +import static com.squareup.javapoet.MethodSpec.CONSTRUCTOR; +import static com.squareup.javapoet.TestUtil.findFirst; import static javax.lang.model.util.ElementFilter.methodsIn; import static org.junit.Assert.fail; @@ -55,15 +58,6 @@ public final class MethodSpecTest { return elements.getTypeElement(clazz.getCanonicalName()); } - private ExecutableElement findFirst(Collection<ExecutableElement> elements, String name) { - for (ExecutableElement executableElement : elements) { - if (executableElement.getSimpleName().toString().equals(name)) { - return executableElement; - } - } - throw new IllegalArgumentException(name + " not found in " + elements); - } - @Test public void nullAnnotationsAddition() { try { MethodSpec.methodBuilder("doSomething").addAnnotations(null); @@ -270,6 +264,59 @@ public final class MethodSpecTest { assertThat(a.hashCode()).isEqualTo(b.hashCode()); } + @Test public void withoutParameterJavaDoc() { + MethodSpec methodSpec = MethodSpec.methodBuilder("getTaco") + .addModifiers(Modifier.PRIVATE) + .addParameter(TypeName.DOUBLE, "money") + .addJavadoc("Gets the best Taco\n") + .build(); + assertThat(methodSpec.toString()).isEqualTo("" + + "/**\n" + + " * Gets the best Taco\n" + + " */\n" + + "private void getTaco(double money) {\n" + + "}\n"); + } + + @Test public void withParameterJavaDoc() { + MethodSpec methodSpec = MethodSpec.methodBuilder("getTaco") + .addParameter(ParameterSpec.builder(TypeName.DOUBLE, "money") + .addJavadoc("the amount required to buy the taco.\n") + .build()) + .addParameter(ParameterSpec.builder(TypeName.INT, "count") + .addJavadoc("the number of Tacos to buy.\n") + .build()) + .addJavadoc("Gets the best Taco money can buy.\n") + .build(); + assertThat(methodSpec.toString()).isEqualTo("" + + "/**\n" + + " * Gets the best Taco money can buy.\n" + + " *\n" + + " * @param money the amount required to buy the taco.\n" + + " * @param count the number of Tacos to buy.\n" + + " */\n" + + "void getTaco(double money, int count) {\n" + + "}\n"); + } + + @Test public void withParameterJavaDocAndWithoutMethodJavadoc() { + MethodSpec methodSpec = MethodSpec.methodBuilder("getTaco") + .addParameter(ParameterSpec.builder(TypeName.DOUBLE, "money") + .addJavadoc("the amount required to buy the taco.\n") + .build()) + .addParameter(ParameterSpec.builder(TypeName.INT, "count") + .addJavadoc("the number of Tacos to buy.\n") + .build()) + .build(); + assertThat(methodSpec.toString()).isEqualTo("" + + "/**\n" + + " * @param money the amount required to buy the taco.\n" + + " * @param count the number of Tacos to buy.\n" + + " */\n" + + "void getTaco(double money, int count) {\n" + + "}\n"); + } + @Test public void duplicateExceptionsIgnored() { ClassName ioException = ClassName.get(IOException.class); ClassName timeoutException = ClassName.get(TimeoutException.class); @@ -302,4 +349,115 @@ public final class MethodSpecTest { assertThat(e.getMessage()).isEqualTo("modifiers == null"); } } + + @Test public void modifyMethodName() { + MethodSpec methodSpec = MethodSpec.methodBuilder("initialMethod") + .build() + .toBuilder() + .setName("revisedMethod") + .build(); + + assertThat(methodSpec.toString()).isEqualTo("" + "void revisedMethod() {\n" + "}\n"); + } + + @Test public void modifyAnnotations() { + MethodSpec.Builder builder = MethodSpec.methodBuilder("foo") + .addAnnotation(Override.class) + .addAnnotation(SuppressWarnings.class); + + builder.annotations.remove(1); + assertThat(builder.build().annotations).hasSize(1); + } + + @Test public void modifyModifiers() { + MethodSpec.Builder builder = MethodSpec.methodBuilder("foo") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC); + + builder.modifiers.remove(1); + assertThat(builder.build().modifiers).containsExactly(Modifier.PUBLIC); + } + + @Test public void modifyParameters() { + MethodSpec.Builder builder = MethodSpec.methodBuilder("foo") + .addParameter(int.class, "source"); + + builder.parameters.remove(0); + assertThat(builder.build().parameters).isEmpty(); + } + + @Test public void modifyTypeVariables() { + TypeVariableName t = TypeVariableName.get("T"); + MethodSpec.Builder builder = MethodSpec.methodBuilder("foo") + .addTypeVariable(t) + .addTypeVariable(TypeVariableName.get("V")); + + builder.typeVariables.remove(1); + assertThat(builder.build().typeVariables).containsExactly(t); + } + + @Test public void ensureTrailingNewline() { + MethodSpec methodSpec = MethodSpec.methodBuilder("method") + .addCode("codeWithNoNewline();") + .build(); + + assertThat(methodSpec.toString()).isEqualTo("" + + "void method() {\n" + + " codeWithNoNewline();\n" + + "}\n"); + } + + /** Ensures that we don't add a duplicate newline if one is already present. */ + @Test public void ensureTrailingNewlineWithExistingNewline() { + MethodSpec methodSpec = MethodSpec.methodBuilder("method") + .addCode("codeWithNoNewline();\n") // Have a newline already, so ensure we're not adding one + .build(); + + assertThat(methodSpec.toString()).isEqualTo("" + + "void method() {\n" + + " codeWithNoNewline();\n" + + "}\n"); + } + + @Test public void controlFlowWithNamedCodeBlocks() { + Map<String, Object> m = new HashMap<>(); + m.put("field", "valueField"); + m.put("threshold", "5"); + + MethodSpec methodSpec = MethodSpec.methodBuilder("method") + .beginControlFlow(named("if ($field:N > $threshold:L)", m)) + .nextControlFlow(named("else if ($field:N == $threshold:L)", m)) + .endControlFlow() + .build(); + + assertThat(methodSpec.toString()).isEqualTo("" + + "void method() {\n" + + " if (valueField > 5) {\n" + + " } else if (valueField == 5) {\n" + + " }\n" + + "}\n"); + } + + @Test public void doWhileWithNamedCodeBlocks() { + Map<String, Object> m = new HashMap<>(); + m.put("field", "valueField"); + m.put("threshold", "5"); + + MethodSpec methodSpec = MethodSpec.methodBuilder("method") + .beginControlFlow("do") + .addStatement(named("$field:N--", m)) + .endControlFlow(named("while ($field:N > $threshold:L)", m)) + .build(); + + assertThat(methodSpec.toString()).isEqualTo("" + + "void method() {\n" + + " do {\n" + + " valueField--;\n" + + " } while (valueField > 5);\n" + + "}\n"); + } + + private static CodeBlock named(String format, Map<String, ?> args){ + return CodeBlock.builder().addNamed(format, args).build(); + } + } diff --git a/src/test/java/com/squareup/javapoet/NameAllocatorTest.java b/src/test/java/com/squareup/javapoet/NameAllocatorTest.java index 1840107..71402c6 100644 --- a/src/test/java/com/squareup/javapoet/NameAllocatorTest.java +++ b/src/test/java/com/squareup/javapoet/NameAllocatorTest.java @@ -18,9 +18,11 @@ package com.squareup.javapoet; import org.junit.Test; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public final class NameAllocatorTest { + @Test public void usage() throws Exception { NameAllocator nameAllocator = new NameAllocator(); assertThat(nameAllocator.newName("foo", 1)).isEqualTo("foo"); @@ -59,6 +61,7 @@ public final class NameAllocatorTest { @Test public void characterMappingInvalidStartButValidPart() throws Exception { NameAllocator nameAllocator = new NameAllocator(); assertThat(nameAllocator.newName("1ab", 1)).isEqualTo("_1ab"); + assertThat(nameAllocator.newName("a-1", 2)).isEqualTo("a_1"); } @Test public void characterMappingInvalidStartIsInvalidPart() throws Exception { diff --git a/src/test/java/com/squareup/javapoet/ParameterSpecTest.java b/src/test/java/com/squareup/javapoet/ParameterSpecTest.java index 2f81866..c3effca 100644 --- a/src/test/java/com/squareup/javapoet/ParameterSpecTest.java +++ b/src/test/java/com/squareup/javapoet/ParameterSpecTest.java @@ -15,23 +15,49 @@ */ package com.squareup.javapoet; +import com.google.testing.compile.CompilationRule; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.Elements; +import org.junit.Before; +import org.junit.Rule; +import javax.lang.model.element.Modifier; import org.junit.Test; import static com.google.common.truth.Truth.assertThat; +import static com.squareup.javapoet.TestUtil.findFirst; +import static javax.lang.model.util.ElementFilter.fieldsIn; +import static javax.lang.model.util.ElementFilter.methodsIn; import static org.junit.Assert.fail; -import javax.lang.model.element.Modifier; - public class ParameterSpecTest { + @Rule public final CompilationRule compilation = new CompilationRule(); + + private Elements elements; + + @Before public void setUp() { + elements = compilation.getElements(); + } + + private TypeElement getElement(Class<?> clazz) { + return elements.getTypeElement(clazz.getCanonicalName()); + } + @Test public void equalsAndHashCode() { ParameterSpec a = ParameterSpec.builder(int.class, "foo").build(); ParameterSpec b = ParameterSpec.builder(int.class, "foo").build(); assertThat(a.equals(b)).isTrue(); assertThat(a.hashCode()).isEqualTo(b.hashCode()); + assertThat(a.toString()).isEqualTo(b.toString()); a = ParameterSpec.builder(int.class, "i").addModifiers(Modifier.STATIC).build(); b = ParameterSpec.builder(int.class, "i").addModifiers(Modifier.STATIC).build(); assertThat(a.equals(b)).isTrue(); assertThat(a.hashCode()).isEqualTo(b.hashCode()); + assertThat(a.toString()).isEqualTo(b.toString()); } @Test public void nullAnnotationsAddition() { @@ -43,4 +69,67 @@ public class ParameterSpecTest { .isEqualTo("annotationSpecs == null"); } } -}
\ No newline at end of file + + final class VariableElementFieldClass { + String name; + } + + @Test public void fieldVariableElement() { + TypeElement classElement = getElement(VariableElementFieldClass.class); + List<VariableElement> methods = fieldsIn(elements.getAllMembers(classElement)); + VariableElement element = findFirst(methods, "name"); + + try { + ParameterSpec.get(element); + fail(); + } catch (IllegalArgumentException exception) { + assertThat(exception).hasMessageThat().isEqualTo("element is not a parameter"); + } + } + + final class VariableElementParameterClass { + public void foo(@Nullable final String bar) { + } + } + + @Test public void parameterVariableElement() { + TypeElement classElement = getElement(VariableElementParameterClass.class); + List<ExecutableElement> methods = methodsIn(elements.getAllMembers(classElement)); + ExecutableElement element = findFirst(methods, "foo"); + VariableElement parameterElement = element.getParameters().get(0); + + assertThat(ParameterSpec.get(parameterElement).toString()) + .isEqualTo("@javax.annotation.Nullable java.lang.String arg0"); + } + + @Test public void addNonFinalModifier() { + List<Modifier> modifiers = new ArrayList<>(); + modifiers.add(Modifier.FINAL); + modifiers.add(Modifier.PUBLIC); + + try { + ParameterSpec.builder(int.class, "foo") + .addModifiers(modifiers); + fail(); + } catch (Exception e) { + assertThat(e.getMessage()).isEqualTo("unexpected parameter modifier: public"); + } + } + + @Test public void modifyAnnotations() { + ParameterSpec.Builder builder = ParameterSpec.builder(int.class, "foo") + .addAnnotation(Override.class) + .addAnnotation(SuppressWarnings.class); + + builder.annotations.remove(1); + assertThat(builder.build().annotations).hasSize(1); + } + + @Test public void modifyModifiers() { + ParameterSpec.Builder builder = ParameterSpec.builder(int.class, "foo") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC); + + builder.modifiers.remove(1); + assertThat(builder.build().modifiers).containsExactly(Modifier.PUBLIC); + } +} diff --git a/src/test/java/com/squareup/javapoet/TestUtil.java b/src/test/java/com/squareup/javapoet/TestUtil.java new file mode 100644 index 0000000..f773d50 --- /dev/null +++ b/src/test/java/com/squareup/javapoet/TestUtil.java @@ -0,0 +1,17 @@ +package com.squareup.javapoet; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import java.util.Collection; + +final class TestUtil { + static <E extends Element> E findFirst(Collection<E> elements, String name) { + for (E element : elements) { + if (element.getSimpleName().toString().equals(name)) { + return element; + } + } + throw new IllegalArgumentException(name + " not found in " + elements); + } +} diff --git a/src/test/java/com/squareup/javapoet/TypeSpecTest.java b/src/test/java/com/squareup/javapoet/TypeSpecTest.java index 9cd22c2..0f67c5c 100644 --- a/src/test/java/com/squareup/javapoet/TypeSpecTest.java +++ b/src/test/java/com/squareup/javapoet/TypeSpecTest.java @@ -17,6 +17,7 @@ package com.squareup.javapoet; import com.google.common.collect.ImmutableMap; import com.google.testing.compile.CompilationRule; +import java.io.File; import java.io.IOException; import java.io.Serializable; import java.math.BigDecimal; @@ -985,6 +986,74 @@ public final class TypeSpecTest { + "}\n"); } + @Test public void simpleNameConflictsWithTypeVariable() { + ClassName inPackage = ClassName.get("com.squareup.tacos", "InPackage"); + ClassName otherType = ClassName.get("com.other", "OtherType"); + ClassName methodInPackage = ClassName.get("com.squareup.tacos", "MethodInPackage"); + ClassName methodOtherType = ClassName.get("com.other", "MethodOtherType"); + TypeSpec gen = TypeSpec.classBuilder("Gen") + .addTypeVariable(TypeVariableName.get("InPackage")) + .addTypeVariable(TypeVariableName.get("OtherType")) + .addField(FieldSpec.builder(inPackage, "inPackage").build()) + .addField(FieldSpec.builder(otherType, "otherType").build()) + .addMethod(MethodSpec.methodBuilder("withTypeVariables") + .addTypeVariable(TypeVariableName.get("MethodInPackage")) + .addTypeVariable(TypeVariableName.get("MethodOtherType")) + .addStatement("$T inPackage = null", methodInPackage) + .addStatement("$T otherType = null", methodOtherType) + .build()) + .addMethod(MethodSpec.methodBuilder("withoutTypeVariables") + .addStatement("$T inPackage = null", methodInPackage) + .addStatement("$T otherType = null", methodOtherType) + .build()) + .addMethod(MethodSpec.methodBuilder("againWithTypeVariables") + .addTypeVariable(TypeVariableName.get("MethodInPackage")) + .addTypeVariable(TypeVariableName.get("MethodOtherType")) + .addStatement("$T inPackage = null", methodInPackage) + .addStatement("$T otherType = null", methodOtherType) + .build()) + // https://github.com/square/javapoet/pull/657#discussion_r205514292 + .addMethod(MethodSpec.methodBuilder("masksEnclosingTypeVariable") + .addTypeVariable(TypeVariableName.get("InPackage")) + .build()) + .addMethod(MethodSpec.methodBuilder("hasSimpleNameThatWasPreviouslyMasked") + .addStatement("$T inPackage = null", inPackage) + .build()) + .build(); + assertThat(toString(gen)).isEqualTo("" + + "package com.squareup.tacos;\n" + + "\n" + + "import com.other.MethodOtherType;\n" + + "\n" + + "class Gen<InPackage, OtherType> {\n" + + " com.squareup.tacos.InPackage inPackage;\n" + + "\n" + + " com.other.OtherType otherType;\n" + + "\n" + + " <MethodInPackage, MethodOtherType> void withTypeVariables() {\n" + + " com.squareup.tacos.MethodInPackage inPackage = null;\n" + + " com.other.MethodOtherType otherType = null;\n" + + " }\n" + + "\n" + + " void withoutTypeVariables() {\n" + + " MethodInPackage inPackage = null;\n" + + " MethodOtherType otherType = null;\n" + + " }\n" + + "\n" + + " <MethodInPackage, MethodOtherType> void againWithTypeVariables() {\n" + + " com.squareup.tacos.MethodInPackage inPackage = null;\n" + + " com.other.MethodOtherType otherType = null;\n" + + " }\n" + + "\n" + + " <InPackage> void masksEnclosingTypeVariable() {\n" + + " }\n" + + "\n" + + " void hasSimpleNameThatWasPreviouslyMasked() {\n" + + " com.squareup.tacos.InPackage inPackage = null;\n" + + " }\n" + + "}\n"); + } + @Test public void originatingElementsIncludesThoseOfNestedTypes() { Element outerElement = Mockito.mock(Element.class); Element innerElement = Mockito.mock(Element.class); @@ -1780,7 +1849,8 @@ public final class TypeSpecTest { + " }\n" + "\n" + " /**\n" - + " * chosen by fair dice roll ;) */\n" + + " * chosen by fair dice roll ;)\n" + + " */\n" + " public int getRandomQuantity() {\n" + " return 4;\n" + " }\n" @@ -1839,7 +1909,7 @@ public final class TypeSpecTest { @Test public void nullModifiersAddition() { try { - TypeSpec.classBuilder("Taco").addModifiers((Modifier) null); + TypeSpec.classBuilder("Taco").addModifiers((Modifier) null).build(); fail(); } catch(IllegalArgumentException expected) { assertThat(expected.getMessage()) @@ -2196,6 +2266,7 @@ public final class TypeSpecTest { @Test public void initializersToBuilder() { // Tests if toBuilder() contains correct static and instance initializers + Element originatingElement = getElement(TypeSpecTest.class); TypeSpec taco = TypeSpec.classBuilder("Taco") .addField(String.class, "foo", Modifier.PRIVATE) .addField(String.class, "FOO", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) @@ -2212,10 +2283,16 @@ public final class TypeSpecTest { .addInitializerBlock(CodeBlock.builder() .addStatement("foo = $S", "FOO") .build()) + .addOriginatingElement(originatingElement) + .alwaysQualify("com.example.AlwaysQualified") .build(); TypeSpec recreatedTaco = taco.toBuilder().build(); assertThat(toString(taco)).isEqualTo(toString(recreatedTaco)); + assertThat(taco.originatingElements) + .containsExactlyElementsIn(recreatedTaco.originatingElements); + assertThat(taco.alwaysQualifiedNames) + .containsExactlyElementsIn(recreatedTaco.alwaysQualifiedNames); TypeSpec initializersAdded = taco.toBuilder() .addInitializerBlock(CodeBlock.builder() @@ -2356,4 +2433,122 @@ public final class TypeSpecTest { assertThat(TypeSpec.enumBuilder(className).addEnumConstant("A").build().name).isEqualTo("Example"); assertThat(TypeSpec.annotationBuilder(className).build().name).isEqualTo("Example"); } + + @Test + public void modifyAnnotations() { + TypeSpec.Builder builder = + TypeSpec.classBuilder("Taco") + .addAnnotation(Override.class) + .addAnnotation(SuppressWarnings.class); + + builder.annotations.remove(1); + assertThat(builder.build().annotations).hasSize(1); + } + + @Test + public void modifyModifiers() { + TypeSpec.Builder builder = + TypeSpec.classBuilder("Taco").addModifiers(Modifier.PUBLIC, Modifier.FINAL); + + builder.modifiers.remove(1); + assertThat(builder.build().modifiers).containsExactly(Modifier.PUBLIC); + } + + @Test + public void modifyFields() { + TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") + .addField(int.class, "source"); + + builder.fieldSpecs.remove(0); + assertThat(builder.build().fieldSpecs).isEmpty(); + } + + @Test + public void modifyTypeVariables() { + TypeVariableName t = TypeVariableName.get("T"); + TypeSpec.Builder builder = + TypeSpec.classBuilder("Taco") + .addTypeVariable(t) + .addTypeVariable(TypeVariableName.get("V")); + + builder.typeVariables.remove(1); + assertThat(builder.build().typeVariables).containsExactly(t); + } + + @Test + public void modifySuperinterfaces() { + TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") + .addSuperinterface(File.class); + + builder.superinterfaces.clear(); + assertThat(builder.build().superinterfaces).isEmpty(); + } + + @Test + public void modifyMethods() { + TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") + .addMethod(MethodSpec.methodBuilder("bell").build()); + + builder.methodSpecs.clear(); + assertThat(builder.build().methodSpecs).isEmpty(); + } + + @Test + public void modifyTypes() { + TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") + .addType(TypeSpec.classBuilder("Bell").build()); + + builder.typeSpecs.clear(); + assertThat(builder.build().typeSpecs).isEmpty(); + } + + @Test + public void modifyEnumConstants() { + TypeSpec constantType = TypeSpec.anonymousClassBuilder("").build(); + TypeSpec.Builder builder = TypeSpec.enumBuilder("Taco") + .addEnumConstant("BELL", constantType) + .addEnumConstant("WUT", TypeSpec.anonymousClassBuilder("").build()); + + builder.enumConstants.remove("WUT"); + assertThat(builder.build().enumConstants).containsExactly("BELL", constantType); + } + + @Test + public void modifyOriginatingElements() { + TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") + .addOriginatingElement(Mockito.mock(Element.class)); + + builder.originatingElements.clear(); + assertThat(builder.build().originatingElements).isEmpty(); + } + + @Test public void javadocWithTrailingLineDoesNotAddAnother() { + TypeSpec spec = TypeSpec.classBuilder("Taco") + .addJavadoc("Some doc with a newline\n") + .build(); + + assertThat(toString(spec)).isEqualTo("" + + "package com.squareup.tacos;\n" + + "\n" + + "/**\n" + + " * Some doc with a newline\n" + + " */\n" + + "class Taco {\n" + + "}\n"); + } + + @Test public void javadocEnsuresTrailingLine() { + TypeSpec spec = TypeSpec.classBuilder("Taco") + .addJavadoc("Some doc with a newline") + .build(); + + assertThat(toString(spec)).isEqualTo("" + + "package com.squareup.tacos;\n" + + "\n" + + "/**\n" + + " * Some doc with a newline\n" + + " */\n" + + "class Taco {\n" + + "}\n"); + } } |