1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.googlejavaformat.java; 16 17 import static com.google.common.truth.Truth.assertThat; 18 import static com.google.common.truth.Truth.assertWithMessage; 19 import static java.nio.charset.StandardCharsets.UTF_8; 20 import static org.junit.Assert.fail; 21 22 import com.google.common.base.Joiner; 23 import com.google.common.io.CharStreams; 24 import com.google.googlejavaformat.java.JavaFormatterOptions.Style; 25 import java.io.ByteArrayInputStream; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.io.InputStreamReader; 29 import java.io.PrintWriter; 30 import java.io.StringWriter; 31 import java.nio.file.Files; 32 import java.nio.file.Path; 33 import org.junit.Rule; 34 import org.junit.Test; 35 import org.junit.rules.TemporaryFolder; 36 import org.junit.runner.RunWith; 37 import org.junit.runners.JUnit4; 38 39 /** Integration test for google-java-format. */ 40 @RunWith(JUnit4.class) 41 public final class FormatterTest { 42 43 @Rule public TemporaryFolder testFolder = new TemporaryFolder(); 44 45 @Test testFormatAosp()46 public void testFormatAosp() throws Exception { 47 // don't forget to misspell "long", or you will be mystified for a while 48 String input = 49 "class A{void b(){while(true){weCanBeCertainThatThisWillEndUpGettingWrapped(" 50 + "because, it, is, just, so, very, very, very, very, looong);}}}"; 51 String expectedOutput = 52 Joiner.on("\n") 53 .join( 54 "class A {", 55 " void b() {", 56 " while (true) {", 57 " weCanBeCertainThatThisWillEndUpGettingWrapped(", 58 " because, it, is, just, so, very, very, very, very, looong);", 59 " }", 60 " }", 61 "}", 62 ""); 63 64 Path tmpdir = testFolder.newFolder().toPath(); 65 Path path = tmpdir.resolve("A.java"); 66 Files.write(path, input.getBytes(UTF_8)); 67 68 StringWriter out = new StringWriter(); 69 StringWriter err = new StringWriter(); 70 71 Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in); 72 String[] args = {"--aosp", path.toString()}; 73 assertThat(main.format(args)).isEqualTo(0); 74 assertThat(out.toString()).isEqualTo(expectedOutput); 75 } 76 77 @Test testFormatNonJavaFiles()78 public void testFormatNonJavaFiles() throws Exception { 79 StringWriter out = new StringWriter(); 80 StringWriter err = new StringWriter(); 81 Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in); 82 83 // should succeed because non-Java files are skipped 84 assertThat(main.format("foo.go")).isEqualTo(0); 85 assertThat(err.toString()).contains("Skipping non-Java file: " + "foo.go"); 86 87 // format still fails on missing files 88 assertThat(main.format("Foo.java")).isEqualTo(1); 89 assertThat(err.toString()).contains("Foo.java: could not read file: "); 90 } 91 92 @Test testFormatStdinStdoutWithDashFlag()93 public void testFormatStdinStdoutWithDashFlag() throws Exception { 94 String input = "class Foo{\n" + "void f\n" + "() {\n" + "}\n" + "}\n"; 95 String expectedOutput = "class Foo {\n" + " void f() {}\n" + "}\n"; 96 97 InputStream in = new ByteArrayInputStream(input.getBytes(UTF_8)); 98 StringWriter out = new StringWriter(); 99 StringWriter err = new StringWriter(); 100 101 InputStream oldIn = System.in; 102 System.setIn(in); 103 104 Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in); 105 assertThat(main.format("-")).isEqualTo(0); 106 assertThat(out.toString()).isEqualTo(expectedOutput); 107 108 System.setIn(oldIn); 109 } 110 111 @Test testFormatLengthUpToEOF()112 public void testFormatLengthUpToEOF() throws Exception { 113 String input = "class Foo{\n" + "void f\n" + "() {\n" + "}\n" + "}\n\n\n\n\n\n"; 114 String expectedOutput = "class Foo {\n" + " void f() {}\n" + "}\n"; 115 116 Path tmpdir = testFolder.newFolder().toPath(); 117 Path path = tmpdir.resolve("Foo.java"); 118 Files.write(path, input.getBytes(UTF_8)); 119 120 StringWriter out = new StringWriter(); 121 StringWriter err = new StringWriter(); 122 123 Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in); 124 String[] args = {"--offset", "0", "--length", String.valueOf(input.length()), path.toString()}; 125 assertThat(main.format(args)).isEqualTo(0); 126 assertThat(out.toString()).isEqualTo(expectedOutput); 127 } 128 129 @Test testFormatLengthOutOfRange()130 public void testFormatLengthOutOfRange() throws Exception { 131 String input = "class Foo{}\n"; 132 133 Path tmpdir = testFolder.newFolder().toPath(); 134 Path path = tmpdir.resolve("Foo.java"); 135 Files.write(path, input.getBytes(UTF_8)); 136 137 StringWriter out = new StringWriter(); 138 StringWriter err = new StringWriter(); 139 140 Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in); 141 String[] args = {"--offset", "0", "--length", "9999", path.toString()}; 142 assertThat(main.format(args)).isEqualTo(1); 143 assertThat(err.toString()) 144 .contains("error: invalid length 9999, offset + length (9999) is outside the file"); 145 } 146 147 @Test blankInClassBody()148 public void blankInClassBody() throws FormatterException { 149 String input = "package test;\nclass T {\n\n}\n"; 150 String output = new Formatter().formatSource(input); 151 String expect = "package test;\n\nclass T {}\n"; 152 assertThat(output).isEqualTo(expect); 153 } 154 155 @Test blankInClassBodyNoTrailing()156 public void blankInClassBodyNoTrailing() throws FormatterException { 157 String input = "package test;\nclass T {\n\n}"; 158 String output = new Formatter().formatSource(input); 159 String expect = "package test;\n\nclass T {}\n"; 160 assertThat(output).isEqualTo(expect); 161 } 162 163 @Test docCommentTrailingBlank()164 public void docCommentTrailingBlank() throws FormatterException { 165 String input = "class T {\n/** asd */\n\nint x;\n}"; 166 String output = new Formatter().formatSource(input); 167 String expect = "class T {\n /** asd */\n int x;\n}\n"; 168 assertThat(output).isEqualTo(expect); 169 } 170 171 @Test blockCommentInteriorTrailingBlank()172 public void blockCommentInteriorTrailingBlank() throws FormatterException { 173 String input = "class T {\n/*\n* asd \n* fgh\n*/ \n\nint x;\n}"; 174 String output = new Formatter().formatSource(input); 175 String expect = "class T {\n /*\n * asd\n * fgh\n */\n\n int x;\n}\n"; 176 assertThat(output).isEqualTo(expect); 177 } 178 179 @Test blockCommentTrailingBlank()180 public void blockCommentTrailingBlank() throws FormatterException { 181 String input = "class T {\n/* asd */ \n\nint x;\n}"; 182 String output = new Formatter().formatSource(input); 183 String expect = "class T {\n /* asd */\n\n int x;\n}\n"; 184 assertThat(output).isEqualTo(expect); 185 } 186 187 @Test lineCommentTrailingBlank()188 public void lineCommentTrailingBlank() throws FormatterException { 189 String input = "class T {\n// asd \n\nint x;\n}"; 190 String output = new Formatter().formatSource(input); 191 String expect = "class T {\n // asd\n\n int x;\n}\n"; 192 assertThat(output).isEqualTo(expect); 193 } 194 195 @Test lineCommentTrailingThinSpace()196 public void lineCommentTrailingThinSpace() throws FormatterException { 197 // The Unicode thin space is matched by CharMatcher.whitespace() but not trim(). 198 String input = "class T {\n // asd\u2009\n}\n"; 199 String output = new Formatter().formatSource(input); 200 String expect = "class T {\n // asd\n}\n"; 201 assertThat(output).isEqualTo(expect); 202 } 203 204 @Test noBlankAfterLineCommentWithInteriorBlankLine()205 public void noBlankAfterLineCommentWithInteriorBlankLine() throws FormatterException { 206 String input = "class T {\n// asd \n\n// dsa \nint x;\n}"; 207 String output = new Formatter().formatSource(input); 208 String expect = "class T {\n // asd\n\n // dsa\n int x;\n}\n"; 209 assertThat(output).isEqualTo(expect); 210 } 211 212 @Test badConstructor()213 public void badConstructor() throws FormatterException { 214 String input = "class X { Y() {} }"; 215 String output = new Formatter().formatSource(input); 216 String expect = "class X {\n Y() {}\n}\n"; 217 assertThat(output).isEqualTo(expect); 218 } 219 220 @Test voidMethod()221 public void voidMethod() throws FormatterException { 222 String input = "class X { void Y() {} }"; 223 String output = new Formatter().formatSource(input); 224 String expect = "class X {\n void Y() {}\n}\n"; 225 assertThat(output).isEqualTo(expect); 226 } 227 228 private static final String UNORDERED_IMPORTS = 229 Joiner.on('\n') 230 .join( 231 "import com.google.common.base.Preconditions;", 232 "", 233 "import static org.junit.Assert.fail;", 234 "import static com.google.truth.Truth.assertThat;", 235 "", 236 "import org.junit.runners.JUnit4;", 237 "import org.junit.runner.RunWith;", 238 "", 239 "import java.util.List;", 240 "", 241 "import javax.annotation.Nullable;"); 242 243 @Test importsNotReorderedByDefault()244 public void importsNotReorderedByDefault() throws FormatterException { 245 String input = 246 "package com.google.example;\n" + UNORDERED_IMPORTS + "\npublic class ExampleTest {}\n"; 247 String output = new Formatter().formatSource(input); 248 String expect = 249 "package com.google.example;\n\n" + UNORDERED_IMPORTS + "\n\npublic class ExampleTest {}\n"; 250 assertThat(output).isEqualTo(expect); 251 } 252 253 @Test importsFixedIfRequested()254 public void importsFixedIfRequested() throws FormatterException { 255 String input = 256 "package com.google.example;\n" 257 + UNORDERED_IMPORTS 258 + "\npublic class ExampleTest {\n" 259 + " @Nullable List<?> xs;\n" 260 + "}\n"; 261 String output = new Formatter().formatSourceAndFixImports(input); 262 String expect = 263 "package com.google.example;\n\n" 264 + "import java.util.List;\n" 265 + "import javax.annotation.Nullable;\n\n" 266 + "public class ExampleTest {\n" 267 + " @Nullable List<?> xs;\n" 268 + "}\n"; 269 assertThat(output).isEqualTo(expect); 270 } 271 272 @Test importOrderingWithoutFormatting()273 public void importOrderingWithoutFormatting() throws IOException, UsageException { 274 importOrdering( 275 "--fix-imports-only", "com/google/googlejavaformat/java/testimports/A.imports-only"); 276 } 277 278 @Test importOrderingAndFormatting()279 public void importOrderingAndFormatting() throws IOException, UsageException { 280 importOrdering(null, "com/google/googlejavaformat/java/testimports/A.imports-and-formatting"); 281 } 282 283 @Test formattingWithoutImportOrdering()284 public void formattingWithoutImportOrdering() throws IOException, UsageException { 285 importOrdering( 286 "--skip-sorting-imports", 287 "com/google/googlejavaformat/java/testimports/A.formatting-and-unused-import-removal"); 288 } 289 290 @Test formattingWithoutRemovingUnusedImports()291 public void formattingWithoutRemovingUnusedImports() throws IOException, UsageException { 292 importOrdering( 293 "--skip-removing-unused-imports", 294 "com/google/googlejavaformat/java/testimports/A.formatting-and-import-sorting"); 295 } 296 importOrdering(String sortArg, String outputResourceName)297 private void importOrdering(String sortArg, String outputResourceName) 298 throws IOException, UsageException { 299 Path tmpdir = testFolder.newFolder().toPath(); 300 Path path = tmpdir.resolve("Foo.java"); 301 302 String inputResourceName = "com/google/googlejavaformat/java/testimports/A.input"; 303 String input = getResource(inputResourceName); 304 String expectedOutput = getResource(outputResourceName); 305 Files.write(path, input.getBytes(UTF_8)); 306 307 StringWriter out = new StringWriter(); 308 StringWriter err = new StringWriter(); 309 Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in); 310 String[] args = 311 sortArg != null 312 ? new String[] {sortArg, "-i", path.toString()} 313 : new String[] {"-i", path.toString()}; 314 main.format(args); 315 316 assertThat(err.toString()).isEmpty(); 317 assertThat(out.toString()).isEmpty(); 318 String output = new String(Files.readAllBytes(path), UTF_8); 319 assertThat(output).isEqualTo(expectedOutput); 320 } 321 getResource(String resourceName)322 private String getResource(String resourceName) throws IOException { 323 try (InputStream stream = getClass().getClassLoader().getResourceAsStream(resourceName)) { 324 assertWithMessage("Missing resource: " + resourceName).that(stream).isNotNull(); 325 return CharStreams.toString(new InputStreamReader(stream, UTF_8)); 326 } 327 } 328 329 // regression test for google-java-format#47 330 @Test testTrailingCommentWithoutTerminalNewline()331 public void testTrailingCommentWithoutTerminalNewline() throws Exception { 332 assertThat(new Formatter().formatSource("/*\n * my comment */")) 333 .isEqualTo("/*\n * my comment */\n"); 334 } 335 336 @Test testEmptyArray()337 public void testEmptyArray() throws Exception { 338 assertThat(new Formatter().formatSource("class T { int x[] = {,}; }")) 339 .isEqualTo("class T {\n int x[] = {,};\n}\n"); 340 } 341 342 @Test stringEscapeLength()343 public void stringEscapeLength() throws Exception { 344 assertThat(new Formatter().formatSource("class T {{ f(\"\\\"\"); }}")) 345 .isEqualTo("class T {\n {\n f(\"\\\"\");\n }\n}\n"); 346 } 347 348 @Test wrapLineComment()349 public void wrapLineComment() throws Exception { 350 assertThat( 351 new Formatter() 352 .formatSource( 353 "class T {\n" 354 + " public static void main(String[] args) { // one long incredibly" 355 + " unbroken sentence moving from topic to topic so that no-one had a" 356 + " chance to interrupt;\n" 357 + " }\n" 358 + "}\n")) 359 .isEqualTo( 360 "class T {\n" 361 + " public static void main(\n" 362 + " String[]\n" 363 + " args) { // one long incredibly unbroken sentence moving" 364 + " from topic to topic so that no-one\n" 365 + " // had a chance to interrupt;\n" 366 + " }\n" 367 + "}\n"); 368 } 369 370 @Test onlyWrapLineCommentOnWhitespace()371 public void onlyWrapLineCommentOnWhitespace() throws Exception { 372 assertThat( 373 new Formatter() 374 .formatSource( 375 "class T {\n" 376 + " public static void main(String[] args) { // one_long_incredibly" 377 + "_unbroken_sentence_moving_from_topic_to_topic_so_that_no-one_had_a" 378 + "_chance_to_interrupt;\n" 379 + " }\n" 380 + "}\n")) 381 .isEqualTo( 382 "class T {\n" 383 + " public static void main(\n" 384 + " String[]\n" 385 + " args) { // one_long_incredibly" 386 + "_unbroken_sentence_moving_from_topic_to_topic_so_that_no-one_had_a" 387 + "_chance_to_interrupt;\n" 388 + " }\n" 389 + "}\n"); 390 } 391 392 @Test onlyWrapLineCommentOnWhitespace_noLeadingWhitespace()393 public void onlyWrapLineCommentOnWhitespace_noLeadingWhitespace() throws Exception { 394 assertThat( 395 new Formatter() 396 .formatSource( 397 "class T {\n" 398 + " public static void main(String[] args) { //one_long_incredibly" 399 + "_unbroken_sentence_moving_from_topic_to_topic_so_that_no-one_had_a" 400 + "_chance_to_interrupt;\n" 401 + " }\n" 402 + "}\n")) 403 .isEqualTo( 404 "class T {\n" 405 + " public static void main(\n" 406 + " String[]\n" 407 + " args) { // one_long_incredibly" 408 + "_unbroken_sentence_moving_from_topic_to_topic_so_that_no-one_had_a" 409 + "_chance_to_interrupt;\n" 410 + " }\n" 411 + "}\n"); 412 } 413 414 @Test throwsFormatterException()415 public void throwsFormatterException() throws Exception { 416 try { 417 new Formatter().formatSourceAndFixImports("package foo; public class {"); 418 fail(); 419 } catch (FormatterException expected) { 420 } 421 } 422 423 @Test blankLinesImportComment()424 public void blankLinesImportComment() throws FormatterException { 425 String withBlank = 426 "package p;\n" 427 + "\n" 428 + "/** test */\n" 429 + "\n" 430 + "import a.A;\n" 431 + "\n" 432 + "class T {\n" 433 + " A a;\n" 434 + "}\n"; 435 String withoutBlank = 436 "package p;\n" 437 + "\n" 438 + "/** test */\n" 439 + "import a.A;\n" 440 + "\n" 441 + "class T {\n" 442 + " A a;\n" 443 + "}\n"; 444 445 // Formatting deletes the blank line between the "javadoc" and the first import. 446 assertThat(new Formatter().formatSource(withBlank)).isEqualTo(withoutBlank); 447 assertThat(new Formatter().formatSourceAndFixImports(withBlank)).isEqualTo(withoutBlank); 448 assertThat(new Formatter().formatSource(withoutBlank)).isEqualTo(withoutBlank); 449 assertThat(new Formatter().formatSourceAndFixImports(withoutBlank)).isEqualTo(withoutBlank); 450 451 // Just fixing imports preserves whitespace around imports. 452 assertThat(RemoveUnusedImports.removeUnusedImports(withBlank)).isEqualTo(withBlank); 453 assertThat(ImportOrderer.reorderImports(withBlank, Style.GOOGLE)).isEqualTo(withBlank); 454 assertThat(RemoveUnusedImports.removeUnusedImports(withoutBlank)).isEqualTo(withoutBlank); 455 assertThat(ImportOrderer.reorderImports(withoutBlank, Style.GOOGLE)).isEqualTo(withoutBlank); 456 } 457 458 @Test dontWrapMoeLineComments()459 public void dontWrapMoeLineComments() throws Exception { 460 assertThat( 461 new Formatter() 462 .formatSource( 463 "class T {\n" 464 + " // MOE: one long incredibly" 465 + " unbroken sentence moving from topic to topic so that no-one had a" 466 + " chance to interrupt;\n" 467 + "}\n")) 468 .isEqualTo( 469 "class T {\n" 470 + " // MOE: one long incredibly" 471 + " unbroken sentence moving from topic to topic so that no-one had a" 472 + " chance to interrupt;\n" 473 + "}\n"); 474 } 475 476 @Test removeTrailingTabsInComments()477 public void removeTrailingTabsInComments() throws Exception { 478 assertThat( 479 new Formatter() 480 .formatSource( 481 "class Foo {\n" 482 + " void f() {\n" 483 + " int x = 0; // comment\t\t\t\n" 484 + " return;\n" 485 + " }\n" 486 + "}\n")) 487 .isEqualTo( 488 "class Foo {\n" 489 + " void f() {\n" 490 + " int x = 0; // comment\n" 491 + " return;\n" 492 + " }\n" 493 + "}\n"); 494 } 495 } 496