blob: 3f6e974d11bc21000430322630df9fc903cf1717 [file] [log] [blame]
/*
* Copyright 2015 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.google.googlejavaformat.java;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
import com.google.common.base.Joiner;
import com.google.common.io.CharStreams;
import com.google.googlejavaformat.java.JavaFormatterOptions.Style;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Integration test for google-java-format. */
@RunWith(JUnit4.class)
public final class FormatterTest {
@Rule public TemporaryFolder testFolder = new TemporaryFolder();
@Test
public void testFormatAosp() throws Exception {
// don't forget to misspell "long", or you will be mystified for a while
String input =
"class A{void b(){while(true){weCanBeCertainThatThisWillEndUpGettingWrapped("
+ "because, it, is, just, so, very, very, very, very, looong);}}}";
String expectedOutput =
Joiner.on("\n")
.join(
"class A {",
" void b() {",
" while (true) {",
" weCanBeCertainThatThisWillEndUpGettingWrapped(",
" because, it, is, just, so, very, very, very, very, looong);",
" }",
" }",
"}",
"");
Path tmpdir = testFolder.newFolder().toPath();
Path path = tmpdir.resolve("A.java");
Files.write(path, input.getBytes(StandardCharsets.UTF_8));
StringWriter out = new StringWriter();
StringWriter err = new StringWriter();
Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in);
String[] args = {"--aosp", path.toString()};
assertThat(main.format(args)).isEqualTo(0);
assertThat(out.toString()).isEqualTo(expectedOutput);
}
@Test
public void testFormatNonJavaFiles() throws Exception {
StringWriter out = new StringWriter();
StringWriter err = new StringWriter();
Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in);
// should succeed because non-Java files are skipped
assertThat(main.format("foo.go")).isEqualTo(0);
assertThat(err.toString()).contains("Skipping non-Java file: " + "foo.go");
// format still fails on missing files
assertThat(main.format("Foo.java")).isEqualTo(1);
assertThat(err.toString()).contains("Foo.java: could not read file: ");
}
@Test
public void testFormatStdinStdoutWithDashFlag() throws Exception {
String input = "class Foo{\n" + "void f\n" + "() {\n" + "}\n" + "}\n";
String expectedOutput = "class Foo {\n" + " void f() {}\n" + "}\n";
InputStream in = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8));
StringWriter out = new StringWriter();
StringWriter err = new StringWriter();
InputStream oldIn = System.in;
System.setIn(in);
Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in);
assertThat(main.format("-")).isEqualTo(0);
assertThat(out.toString()).isEqualTo(expectedOutput);
System.setIn(oldIn);
}
@Test
public void testFormatLengthUpToEOF() throws Exception {
String input = "class Foo{\n" + "void f\n" + "() {\n" + "}\n" + "}\n\n\n\n\n\n";
String expectedOutput = "class Foo {\n" + " void f() {}\n" + "}\n";
Path tmpdir = testFolder.newFolder().toPath();
Path path = tmpdir.resolve("Foo.java");
Files.write(path, input.getBytes(StandardCharsets.UTF_8));
StringWriter out = new StringWriter();
StringWriter err = new StringWriter();
Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in);
String[] args = {"--offset", "0", "--length", String.valueOf(input.length()), path.toString()};
assertThat(main.format(args)).isEqualTo(0);
assertThat(out.toString()).isEqualTo(expectedOutput);
}
@Test
public void testFormatLengthOutOfRange() throws Exception {
String input = "class Foo{}\n";
Path tmpdir = testFolder.newFolder().toPath();
Path path = tmpdir.resolve("Foo.java");
Files.write(path, input.getBytes(StandardCharsets.UTF_8));
StringWriter out = new StringWriter();
StringWriter err = new StringWriter();
Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in);
String[] args = {"--offset", "0", "--length", "9999", path.toString()};
assertThat(main.format(args)).isEqualTo(1);
assertThat(err.toString())
.contains("error: invalid length 9999, offset + length (9999) is outside the file");
}
@Test
public void blankInClassBody() throws FormatterException {
String input = "package test;\nclass T {\n\n}\n";
String output = new Formatter().formatSource(input);
String expect = "package test;\n\nclass T {}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void blankInClassBodyNoTrailing() throws FormatterException {
String input = "package test;\nclass T {\n\n}";
String output = new Formatter().formatSource(input);
String expect = "package test;\n\nclass T {}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void docCommentTrailingBlank() throws FormatterException {
String input = "class T {\n/** asd */\n\nint x;\n}";
String output = new Formatter().formatSource(input);
String expect = "class T {\n /** asd */\n int x;\n}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void blockCommentInteriorTrailingBlank() throws FormatterException {
String input = "class T {\n/*\n* asd \n* fgh\n*/ \n\nint x;\n}";
String output = new Formatter().formatSource(input);
String expect = "class T {\n /*\n * asd\n * fgh\n */\n\n int x;\n}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void blockCommentTrailingBlank() throws FormatterException {
String input = "class T {\n/* asd */ \n\nint x;\n}";
String output = new Formatter().formatSource(input);
String expect = "class T {\n /* asd */\n\n int x;\n}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void lineCommentTrailingBlank() throws FormatterException {
String input = "class T {\n// asd \n\nint x;\n}";
String output = new Formatter().formatSource(input);
String expect = "class T {\n // asd\n\n int x;\n}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void lineCommentTrailingThinSpace() throws FormatterException {
// The Unicode thin space is matched by CharMatcher.whitespace() but not trim().
String input = "class T {\n // asd\u2009\n}\n";
String output = new Formatter().formatSource(input);
String expect = "class T {\n // asd\n}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void noBlankAfterLineCommentWithInteriorBlankLine() throws FormatterException {
String input = "class T {\n// asd \n\n// dsa \nint x;\n}";
String output = new Formatter().formatSource(input);
String expect = "class T {\n // asd\n\n // dsa\n int x;\n}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void badConstructor() throws FormatterException {
String input = "class X { Y() {} }";
String output = new Formatter().formatSource(input);
String expect = "class X {\n Y() {}\n}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void voidMethod() throws FormatterException {
String input = "class X { void Y() {} }";
String output = new Formatter().formatSource(input);
String expect = "class X {\n void Y() {}\n}\n";
assertThat(output).isEqualTo(expect);
}
private static final String UNORDERED_IMPORTS =
Joiner.on('\n')
.join(
"import com.google.common.base.Preconditions;",
"",
"import static org.junit.Assert.fail;",
"import static com.google.truth.Truth.assertThat;",
"",
"import org.junit.runners.JUnit4;",
"import org.junit.runner.RunWith;",
"",
"import java.util.List;",
"",
"import javax.annotations.Nullable;");
@Test
public void importsNotReorderedByDefault() throws FormatterException {
String input =
"package com.google.example;\n" + UNORDERED_IMPORTS + "\npublic class ExampleTest {}\n";
String output = new Formatter().formatSource(input);
String expect =
"package com.google.example;\n\n" + UNORDERED_IMPORTS + "\n\npublic class ExampleTest {}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void importsFixedIfRequested() throws FormatterException {
String input =
"package com.google.example;\n"
+ UNORDERED_IMPORTS
+ "\npublic class ExampleTest {\n"
+ " @Nullable List<?> xs;\n"
+ "}\n";
String output = new Formatter().formatSourceAndFixImports(input);
String expect =
"package com.google.example;\n\n"
+ "import java.util.List;\n"
+ "import javax.annotations.Nullable;\n\n"
+ "public class ExampleTest {\n"
+ " @Nullable List<?> xs;\n"
+ "}\n";
assertThat(output).isEqualTo(expect);
}
@Test
public void importOrderingWithoutFormatting() throws IOException, UsageException {
importOrdering(
"--fix-imports-only", "com/google/googlejavaformat/java/testimports/A.imports-only");
}
@Test
public void importOrderingAndFormatting() throws IOException, UsageException {
importOrdering(null, "com/google/googlejavaformat/java/testimports/A.imports-and-formatting");
}
@Test
public void formattingWithoutImportOrdering() throws IOException, UsageException {
importOrdering(
"--skip-sorting-imports",
"com/google/googlejavaformat/java/testimports/A.formatting-and-unused-import-removal");
}
@Test
public void formattingWithoutRemovingUnusedImports() throws IOException, UsageException {
importOrdering(
"--skip-removing-unused-imports",
"com/google/googlejavaformat/java/testimports/A.formatting-and-import-sorting");
}
private void importOrdering(String sortArg, String outputResourceName)
throws IOException, UsageException {
Path tmpdir = testFolder.newFolder().toPath();
Path path = tmpdir.resolve("Foo.java");
String inputResourceName = "com/google/googlejavaformat/java/testimports/A.input";
String input = getResource(inputResourceName);
String expectedOutput = getResource(outputResourceName);
Files.write(path, input.getBytes(StandardCharsets.UTF_8));
StringWriter out = new StringWriter();
StringWriter err = new StringWriter();
Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in);
String[] args =
sortArg != null
? new String[] {sortArg, "-i", path.toString()}
: new String[] {"-i", path.toString()};
main.format(args);
assertThat(err.toString()).isEmpty();
assertThat(out.toString()).isEmpty();
String output = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
assertThat(output).isEqualTo(expectedOutput);
}
private String getResource(String resourceName) throws IOException {
try (InputStream stream = getClass().getClassLoader().getResourceAsStream(resourceName)) {
assertWithMessage("Missing resource: " + resourceName).that(stream).isNotNull();
return CharStreams.toString(new InputStreamReader(stream, StandardCharsets.UTF_8));
}
}
// regression test for google-java-format#47
@Test
public void testTrailingCommentWithoutTerminalNewline() throws Exception {
assertThat(new Formatter().formatSource("/*\n * my comment */"))
.isEqualTo("/*\n * my comment */\n");
}
@Test
public void testEmptyArray() throws Exception {
assertThat(new Formatter().formatSource("class T { int x[] = {,}; }"))
.isEqualTo("class T {\n int x[] = {,};\n}\n");
}
@Test
public void stringEscapeLength() throws Exception {
assertThat(new Formatter().formatSource("class T {{ f(\"\\\"\"); }}"))
.isEqualTo("class T {\n {\n f(\"\\\"\");\n }\n}\n");
}
@Test
public void wrapLineComment() throws Exception {
assertThat(
new Formatter()
.formatSource(
"class T {\n"
+ " public static void main(String[] args) { // one long incredibly"
+ " unbroken sentence moving from topic to topic so that no-one had a"
+ " chance to interrupt;\n"
+ " }\n"
+ "}\n"))
.isEqualTo(
"class T {\n"
+ " public static void main(\n"
+ " String[]\n"
+ " args) { // one long incredibly unbroken sentence moving"
+ " from topic to topic so that no-one\n"
+ " // had a chance to interrupt;\n"
+ " }\n"
+ "}\n");
}
@Test
public void onlyWrapLineCommentOnWhitespace() throws Exception {
assertThat(
new Formatter()
.formatSource(
"class T {\n"
+ " public static void main(String[] args) { // one_long_incredibly"
+ "_unbroken_sentence_moving_from_topic_to_topic_so_that_no-one_had_a"
+ "_chance_to_interrupt;\n"
+ " }\n"
+ "}\n"))
.isEqualTo(
"class T {\n"
+ " public static void main(\n"
+ " String[]\n"
+ " args) { // one_long_incredibly"
+ "_unbroken_sentence_moving_from_topic_to_topic_so_that_no-one_had_a"
+ "_chance_to_interrupt;\n"
+ " }\n"
+ "}\n");
}
@Test
public void onlyWrapLineCommentOnWhitespace_noLeadingWhitespace() throws Exception {
assertThat(
new Formatter()
.formatSource(
"class T {\n"
+ " public static void main(String[] args) { //one_long_incredibly"
+ "_unbroken_sentence_moving_from_topic_to_topic_so_that_no-one_had_a"
+ "_chance_to_interrupt;\n"
+ " }\n"
+ "}\n"))
.isEqualTo(
"class T {\n"
+ " public static void main(\n"
+ " String[]\n"
+ " args) { // one_long_incredibly"
+ "_unbroken_sentence_moving_from_topic_to_topic_so_that_no-one_had_a"
+ "_chance_to_interrupt;\n"
+ " }\n"
+ "}\n");
}
@Test
public void throwsFormatterException() throws Exception {
try {
new Formatter().formatSourceAndFixImports("package foo; public class {");
fail();
} catch (FormatterException expected) {
}
}
@Test
public void blankLinesImportComment() throws FormatterException {
String withBlank =
"package p;\n"
+ "\n"
+ "/** test */\n"
+ "\n"
+ "import a.A;\n"
+ "\n"
+ "class T {\n"
+ " A a;\n"
+ "}\n";
String withoutBlank =
"package p;\n"
+ "\n"
+ "/** test */\n"
+ "import a.A;\n"
+ "\n"
+ "class T {\n"
+ " A a;\n"
+ "}\n";
// Formatting deletes the blank line between the "javadoc" and the first import.
assertThat(new Formatter().formatSource(withBlank)).isEqualTo(withoutBlank);
assertThat(new Formatter().formatSourceAndFixImports(withBlank)).isEqualTo(withoutBlank);
assertThat(new Formatter().formatSource(withoutBlank)).isEqualTo(withoutBlank);
assertThat(new Formatter().formatSourceAndFixImports(withoutBlank)).isEqualTo(withoutBlank);
// Just fixing imports preserves whitespace around imports.
assertThat(RemoveUnusedImports.removeUnusedImports(withBlank)).isEqualTo(withBlank);
assertThat(ImportOrderer.reorderImports(withBlank, Style.GOOGLE)).isEqualTo(withBlank);
assertThat(RemoveUnusedImports.removeUnusedImports(withoutBlank)).isEqualTo(withoutBlank);
assertThat(ImportOrderer.reorderImports(withoutBlank, Style.GOOGLE)).isEqualTo(withoutBlank);
}
@Test
public void dontWrapMoeLineComments() throws Exception {
assertThat(
new Formatter()
.formatSource(
"class T {\n"
+ " // MOE: one long incredibly"
+ " unbroken sentence moving from topic to topic so that no-one had a"
+ " chance to interrupt;\n"
+ "}\n"))
.isEqualTo(
"class T {\n"
+ " // MOE: one long incredibly"
+ " unbroken sentence moving from topic to topic so that no-one had a"
+ " chance to interrupt;\n"
+ "}\n");
}
@Test
public void removeTrailingTabsInComments() throws Exception {
assertThat(
new Formatter()
.formatSource(
"class Foo {\n"
+ " void f() {\n"
+ " int x = 0; // comment\t\t\t\n"
+ " return;\n"
+ " }\n"
+ "}\n"))
.isEqualTo(
"class Foo {\n"
+ " void f() {\n"
+ " int x = 0; // comment\n"
+ " return;\n"
+ " }\n"
+ "}\n");
}
}