google-java-format-master/core/src/test/java/com/google/googlejavaformat/java/JavadocFormattingTest.java
/*
 * Copyright 2016 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 java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.base.Joiner;
import com.google.common.io.ByteStreams;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests formatting javadoc. */
@RunWith(JUnit4.class)
public final class JavadocFormattingTest {

  private final Formatter formatter = new Formatter();

  @Test
  public void notJavadoc() {
    String[] input = {
      "/**/", //
      "class Test {}",
    };
    String[] expected = {
      "/**/", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void empty() {
    String[] input = {
      "/***/", //
      "class Test {}",
    };
    String[] expected = {
      "/***/", "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void emptyMultipleLines() {
    String[] input = {
      "/**", //
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/** */", "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void simple() {
    String[] input = {
      "/** */", //
      "class Test {}",
    };
    String[] expected = {
      "/** */", "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void commentMostlyUntouched() {
    // This test isn't necessarily what we'd want to do, but it's what we do now, and it's OK-ish.
    String[] input = {
      "/**",
      " * Foo.",
      " *",
      " *  <!--",
      "*abc",
      " *   def   ",
      " * </tr>",
      " *-->bar",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * Foo.",
      " * <!--",
      " *abc",
      " *   def",
      " * </tr>",
      " *-->",
      " * bar",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void moeComments() {
    String[] input = {
      "/**",
      " * Deatomizes the given user.",
      " * <!-- M" + "OE:begin_intracomment_strip -->",
      " * See deatomizer-v5 for the design doc.",
      " * <!-- M" + "OE:end_intracomment_strip -->",
      " * To reatomize, call {@link reatomize}.",
      " *",
      " * <!-- M" + "OE:begin_intracomment_strip -->",
      " * <p>This method is used in the Google teleporter.",
      " *",
      " * <p>Yes, we have a teleporter.",
      " * <!-- M" + "OE:end_intracomment_strip -->",
      " *",
      " * @param user the person to teleport.",
      " *     <!-- M" + "OE:begin_intracomment_strip -->",
      " *     Users must sign deatomize-waiver ahead of time.",
      " *     <!-- M" + "OE:end_intracomment_strip -->",
      " * <!-- M" + "OE:begin_intracomment_strip -->",
      " * @deprecated Sometimes turns the user into a goat.",
      " * <!-- M" + "OE:end_intracomment_strip -->",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * Deatomizes the given user.",
      " * <!-- M" + "OE:begin_intracomment_strip -->",
      " * See deatomizer-v5 for the design doc.",
      " * <!-- M" + "OE:end_intracomment_strip -->",
      " * To reatomize, call {@link reatomize}.",
      " *",
      " * <!-- M" + "OE:begin_intracomment_strip -->",
      " * <p>This method is used in the Google teleporter.",
      " *",
      " * <p>Yes, we have a teleporter.",
      " * <!-- M" + "OE:end_intracomment_strip -->",
      " *",
      " * @param user the person to teleport.",
      " *     <!-- M" + "OE:begin_intracomment_strip -->",
      " *     Users must sign deatomize-waiver ahead of time.",
      " *     <!-- M" + "OE:end_intracomment_strip -->",
      " * <!-- M" + "OE:begin_intracomment_strip -->",
      " * @deprecated Sometimes turns the user into a goat.",
      " * <!-- M" + "OE:end_intracomment_strip -->",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void moeCommentBeginOnlyInMiddleOfDoc() {
    // We don't really care what happens here so long as we don't explode.
    String[] input = {
      "/**", //
      " * Foo.",
      " * <!-- M" + "OE:begin_intracomment_strip -->",
      " * Bar.",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * Foo.",
      " * <!-- M" + "OE:begin_intracomment_strip -->",
      " * Bar.",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void moeCommentBeginOnlyAtEndOfDoc() {
    // We don't really care what happens here so long as we don't explode.
    // TODO(cpovirk): OK, maybe try to leave it in....
    String[] input = {
      "/**", //
      " * Foo.",
      " * <!-- M" + "OE:begin_intracomment_strip -->",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/** Foo. */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void moeCommentEndOnly() {
    // We don't really care what happens here so long as we don't explode.
    String[] input = {
      "/**", //
      " * Foo.",
      " * <!-- M" + "OE:end_intracomment_strip -->",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * Foo.",
      " * <!-- M" + "OE:end_intracomment_strip -->",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void tableMostlyUntouched() {
    String[] input = {
      "/**",
      " * Foo.",
      " *",
      " *  <table>",
      "*<tr><td>a<td>b</tr>",
      " * <tr>",
      " * <td>A",
      " *     <td>B",
      " * </tr>",
      " *</table>",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * Foo.",
      " *",
      " * <table>",
      " * <tr><td>a<td>b</tr>",
      " * <tr>",
      " * <td>A",
      " *     <td>B",
      " * </tr>",
      " * </table>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void preMostlyUntouched() {
    /*
     * Arguably we shouldn't insert the space between "*" and "4," since doing so changes the
     * rendered HTML output (by inserting a space there). However, inserting a space between "*" and
     * "</pre>" (which has no impact on the rendered HTML AFAIK) is a good thing, and inserting
     * similar spaces in the case of <table> is good, too. And if "* 4" breaks a user's intended
     * formatting, that user can fix it up, just as that user would have to fix up the "*4"
     * style violation. The main downside to "* 4" is that the user might not notice that we made
     * the change at all. (We've also slightly complicated NEWLINE_PATTERN and writeNewline to
     * accommodate it.)
     */
    String[] input = {
      "/**", //
      " * Example:",
      " *",
      " *  <pre>",
      "*    1 2<br>    3   ",
      " *4 5 6",
      "7 8",
      " *</pre>",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * Example:",
      " *",
      " * <pre>",
      " *    1 2<br>    3",
      " * 4 5 6",
      " * 7 8",
      " * </pre>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void preCodeExample() {
    // We should figure out whether we want a newline or blank line before <pre> or not.
    String[] input = {
      "/**",
      " * Example:",
      " *",
      " * <pre>   {@code",
      " *",
      " *   Abc.def(foo, 7, true); // blah}</pre>",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * Example:",
      " *",
      " * <pre>{@code",
      " * Abc.def(foo, 7, true); // blah",
      " * }</pre>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void preNotWrapped() {
    String[] input = {
      "/**",
      " * Example:",
      " *",
      " * <pre>",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "456789012 45678901",
      " * </pre>",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * Example:",
      " *",
      " * <pre>",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "456789012 45678901",
      " * </pre>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void javaCodeInPre() {
    String[] input = {
      "/**",
      " * Example:",
      " *",
      " *<pre>",
      " * aaaaa    |   a  |   +",
      " * \"bbbb    |   b  |  \"",
      " *</pre>",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * Example:",
      " *",
      " * <pre>",
      " * aaaaa    |   a  |   +",
      " * \"bbbb    |   b  |  \"",
      " * </pre>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void joinLines() {
    String[] input = {
      "/**", //
      " * foo",
      " * bar",
      " * baz",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/** foo bar baz */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void oneLinerIs100() {
    String[] input = {
      "/**",
      " * 567890123 567890123 567890123 567890123 567890123 567890123 567890123 567890123 "
          + "567890123 567",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/** 567890123 567890123 567890123 567890123 567890123 567890123 567890123 567890123 "
          + "567890123 567 */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void oneLinerWouldBe101() {
    String[] input = {
      "/**",
      " * 567890123 567890123 567890123 567890123 567890123 567890123 567890123 567890123 "
          + "567890123 5678",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * 567890123 567890123 567890123 567890123 567890123 567890123 567890123 567890123 "
          + "567890123 5678",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void multilineWrap() {
    String[] input = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "456789012 45678901",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "456789012",
      " * 45678901",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void tooLong() {
    String[] input = {
      "/**",
      " * abc",
      " *",
      " * <p>789012345678901234567890123456789012345678901234567890123456789012345678901234567"
          + "8901234567890123456",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * abc",
      " *",
      " * <p>789012345678901234567890123456789012345678901234567890123456789012345678901234567"
          + "8901234567890123456",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void joinedTokens() {
    /*
     * Originally, 4, <b>, and 8901 are separate tokens. Test that we join them (and thus don't
     * split them across lines).
     */
    String[] input = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "456789012 4<b>8901",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "456789012",
      " * 4<b>8901",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void joinedAtSign() {
    /*
     * The last 456789012 would fit on the first line with the others. But putting it there would
     * mean the next line would start with @5678901, which would then be interpreted as a tag.
     */
    String[] input = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "456789012 @5678901",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012",
      " * 456789012 @5678901",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void joinedMultipleAtSign() {
    // This is the same as above except that it tests multiple consecutive @... tokens.
    String[] input = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "@56789012 @5678901",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012",
      " * 456789012 @56789012 @5678901",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void noAsterisk() {
    String[] input = {
      "/**", //
      " abc<p>def",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * abc",
      " *",
      " * <p>def",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void significantAsterisks() {
    String[] input = {
      "/** *", //
      " * *",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/** * * */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void links() {
    String[] input = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "456789012 4567 <a",
      " * href=foo>foo</a>.",
      " *",
      " * <p>789012 456789012 456789012 456789012 456789012 456789012 456789012 456789 "
          + "<a href=foo>",
      " * foo</a>.",
      " *",
      " * <p>789012 456789012 456789012 456789012 456789012 456789012 456789012 4567890 "
          + "<a href=foo>",
      " * foo</a>.",
      " *",
      " * <p><a href=foo>",
      " * foo</a>.",
      " *",
      " * <p>foo <a href=bar>",
      " * bar</a>.",
      " *",
      " * <p>foo-<a href=bar>",
      " * bar</a>.",
      " *",
      " * <p>foo<a href=bar>",
      " * bar</a>.",
      " *",
      " * <p><a href=foo>foo</a> bar.",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * 456789012 456789012 456789012 456789012 456789012 456789012 456789012 456789012 "
          + "456789012 4567 <a",
      " * href=foo>foo</a>.",
      " *",
      " * <p>789012 456789012 456789012 456789012 456789012 456789012 456789012 456789 "
          + "<a href=foo>foo</a>.",
      " *",
      " * <p>789012 456789012 456789012 456789012 456789012 456789012 456789012 4567890 "
          + "<a href=foo>",
      " * foo</a>.",
      " *",
      " * <p><a href=foo>foo</a>.",
      " *",
      " * <p>foo <a href=bar>bar</a>.",
      " *",
      " * <p>foo-<a href=bar>bar</a>.",
      " *",
      /*
       * In this next case, we've removed a space from the output. Fortunately, the depot doesn't
       * appear to contain any occurrences of this pattern. And if it does, the better fix is to
       * insert a space before <a href> rather than after.
       */
      " * <p>foo<a href=bar>bar</a>.",
      " *",
      " * <p><a href=foo>foo</a> bar.",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void heading() {
    String[] input = {
      "/**", //
      " * abc<h1>def</h1>ghi",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * abc",
      " *",
      " * <h1>def</h1>",
      " *",
      " * ghi",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void blockquote() {
    String[] input = {
      "/**", //
      " * abc<blockquote><p>def</blockquote>ghi",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * abc",
      " *",
      " * <blockquote>",
      " *",
      " * <p>def",
      " *",
      " * </blockquote>",
      " *",
      " * ghi",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void lists() {
    String[] input = {
      "/**", //
      "* hi",
      "*",
      "* <ul>",
      "* <li>",
      "* <ul>",
      "* <li>a</li>",
      "* </ul>",
      "* </li>",
      "* </ul>",
      "*/",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * hi",
      " *",
      " * <ul>",
      " *   <li>",
      " *       <ul>",
      " *         <li>a",
      " *       </ul>",
      " * </ul>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void lists2() {
    String[] input = {
      "/**", //
      " * Foo.",
      " *",
      " * <ul><li>1<ul><li>1a<li>1b</ul>more 1<p>still more 1<li>2</ul>",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * Foo.",
      " *",
      " * <ul>",
      " *   <li>1",
      " *       <ul>",
      " *         <li>1a",
      " *         <li>1b",
      " *       </ul>",
      " *       more 1",
      " *       <p>still more 1",
      " *   <li>2",
      " * </ul>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void closeInnerListStillNewline() {
    String[] input = {
      "/**", //
      " * Foo.",
      " *",
      " * <ul><li><ul><li>a</ul>b</ul>",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * Foo.",
      " *",
      " * <ul>",
      " *   <li>",
      " *       <ul>",
      " *         <li>a",
      " *       </ul>",
      " *       b",
      " * </ul>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void listItemWrap() {
    String[] input = {
      "/**", //
      " * Foo.",
      " *",
      " * <ul><li>234567890 234567890 234567890 234567890 234567890 234567890 234567890 234567890"
          + " 234567890 234567890</ul>",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * Foo.",
      " *",
      " * <ul>",
      " *   <li>234567890 234567890 234567890 234567890 234567890 234567890 234567890 234567890"
          + " 234567890",
      " *       234567890",
      " * </ul>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void unclosedList() {
    String[] input = {
      "/**", //
      " * Foo.",
      " *",
      " * <ul><li>1",
      " * @return blah",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * Foo.",
      " *",
      " * <ul>",
      " *   <li>1",
      " *",
      " * @return blah",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void br() {
    String[] input = {
      "/**", //
      " * abc<br>def",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * abc<br>",
      " * def",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void brSpaceBug() {
    // TODO(b/28983091): Remove the space before <br> here.
    String[] input = {
      "/**", //
      " * abc <br>def",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * abc <br>",
      " * def",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void brAtSignBug() {
    /*
     * This is a bug -- more of a "spec" bug than an implementation bug, and hard to fix.
     * Fortunately, some very quick searching didn't turn up any instances in the Google codebase.
     */
    String[] input = {
      "/**", //
      " * abc<br>@foo ",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * abc<br>",
      " * @foo", // interpreted as a block tag now!
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void unicodeCharacterCountArguableBug() {
    /*
     * We might prefer for multi-char characters like 𝄞 to be treated as taking up one column (or
     * perhaps for all characters to be treated based on their width in monospace fonts). But
     * currently we just count chars.
     */
    String[] input = {
      "/**",
      " * 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12 "
          + "456789𝄞12 456789𝄞",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12 456789𝄞12",
      " * 456789𝄞12 456789𝄞",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void blankLineBeforeParams() {
    String[] input = {
      "/**", //
      " * hello world",
      " * @param this is a param",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * hello world",
      " *",
      " * @param this is a param",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void onlyParams() {
    String[] input = {
      "/**", //
      " *",
      " *",
      " * @param this is a param",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * @param this is a param",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void paramsContinuationIndented() {
    String[] input = {
      "/**", //
      " * hello world",
      " *",
      " * @param foo 567890123 567890123 567890123 567890123 567890123 567890123 567890123"
          + " 567890123 567890123",
      " * @param bar another",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * hello world",
      " *",
      " * @param foo 567890123 567890123 567890123 567890123 567890123 567890123 567890123"
          + " 567890123",
      " *     567890123",
      " * @param bar another",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void paramsOtherIndents() {
    String[] input = {
      "/**", //
      " * hello world",
      " *",
      " * @param foo a<p>b<ul><li>a<ul><li>x</ul></ul>",
      " * @param bar another",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * hello world",
      " *",
      " * @param foo a",
      " *     <p>b",
      " *     <ul>",
      " *       <li>a",
      " *           <ul>",
      " *             <li>x",
      " *           </ul>",
      " *     </ul>",
      " *", // TODO(cpovirk): Ideally we would probably eliminate this.
      " * @param bar another",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void paragraphTag() {
    String[] input = {
      "class Test {",
      "  /**",
      "   * hello<p>world",
      "   */",
      "  void f() {}",
      "",
      "  /**",
      "   * hello",
      "   * <p>",
      "   * world",
      "   */",
      "  void f() {}",
      "}",
    };
    String[] expected = {
      "class Test {",
      "  /**",
      "   * hello",
      "   *",
      "   * <p>world",
      "   */",
      "  void f() {}",
      "",
      "  /**",
      "   * hello",
      "   *",
      "   * <p>world",
      "   */",
      "  void f() {}",
      "}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void xhtmlParagraphTag() {
    String[] input = {
      "class Test {",
      "  /**",
      "   * hello<p/>world",
      "   */",
      "  void f() {}",
      "",
      "}",
    };
    String[] expected = {
      "class Test {",
      "  /**",
      "   * hello",
      "   *",
      "   * <p>world",
      "   */",
      "  void f() {}",
      "}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void removeInitialParagraphTag() {
    String[] input = {
      "/**", //
      " * <p>hello<p>world",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * hello",
      " *",
      " * <p>world",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void inferParagraphTags() {
    String[] input = {
      "/**",
      " *",
      " *",
      " * foo",
      " * foo",
      " *",
      " *",
      " * foo",
      " *",
      " * bar",
      " *",
      " * <pre>",
      " *",
      " * baz",
      " *",
      " * </pre>",
      " *",
      " * <ul>",
      " * <li>foo",
      " *",
      " * bar",
      " * </ul>",
      " *",
      " *",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * foo foo",
      " *",
      " * <p>foo",
      " *",
      " * <p>bar",
      " *",
      " * <pre>",
      " *",
      " * baz",
      " *",
      " * </pre>",
      " *",
      " * <ul>",
      " *   <li>foo",
      " *       <p>bar",
      " * </ul>",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void paragraphTagNewlines() throws Exception {
    String input =
        new String(
            ByteStreams.toByteArray(getClass().getResourceAsStream("testjavadoc/B28750242.input")),
            UTF_8);
    String expected =
        new String(
            ByteStreams.toByteArray(getClass().getResourceAsStream("testjavadoc/B28750242.output")),
            UTF_8);
    String output = formatter.formatSource(input);
    assertThat(output).isEqualTo(expected);
  }

  @Test
  public void listItemSpaces() throws Exception {
    String input =
        new String(
            ByteStreams.toByteArray(getClass().getResourceAsStream("testjavadoc/B31404367.input")),
            UTF_8);
    String expected =
        new String(
            ByteStreams.toByteArray(getClass().getResourceAsStream("testjavadoc/B31404367.output")),
            UTF_8);
    String output = formatter.formatSource(input);
    assertThat(output).isEqualTo(expected);
  }

  @Test
  public void htmlTagsInCode() {
    String[] input = {
      "/** abc {@code {} <p> <li> <pre> <table>} def */", //
      "class Test {}",
    };
    String[] expected = {
      "/** abc {@code {} <p> <li> <pre> <table>} def */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void loneBraceDoesNotStartInlineTag() {
    String[] input = {
      "/** {  <p> } */", //
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * {",
      " *",
      " * <p>}",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void unicodeEscapesNotReplaced() {
    // Test that we don't replace them with their interpretations.
    String[] input = {
      "/** foo \\u0000 bar \\u6c34 baz */", //
      "class Test {}",
    };
    String[] expected = {
      "/** foo \\u0000 bar \\u6c34 baz */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void unicodeEscapesNotInterpretedBug() {
    /*
     * In theory, \u003C should be treated exactly like <, and so too should the escaped versions of
     * @, *, and other special chars. We don't recognize that, though, so we don't put what is
     * effectively "<p>" on a new line.
     */
    String[] input = {
      "/** a\\u003Cp>b */", //
      "class Test {}",
    };
    String[] expected = {
      "/** a\\u003Cp>b */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void trailingLink() {
    // Eclipse's parser seems to want to discard the line break after {@link}. Test that we see it.
    String[] input = {
      "/**", //
      " * abc {@link Foo}",
      " * def",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/** abc {@link Foo} def */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void codeInCode() {
    // Eclipse's parser seems to get confused at the second {@code}. Test that we handle it.
    String[] input = {
      "/** abc {@code {@code foo}} def */", //
      "class Test {}",
    };
    String[] expected = {
      "/** abc {@code {@code foo}} def */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void quotedTextSplitAcrossLinks() {
    /*
     * This demonstrates one of multiple reasons that we can't hand the Javadoc *content* to
     * Eclipse's lexer as if it were Java code.
     */
    String[] input = {
      "/**", //
      " * abc \"foo",
      " * bar baz\" def",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/** abc \"foo bar baz\" def */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void standardizeTags() {
    String[] input = {
      "/**",
      " * foo",
      " *",
      " * <P>bar",
      " *",
      " * <p class=clazz>baz<BR>",
      " * baz",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**",
      " * foo",
      " *",
      " * <p>bar",
      " *",
      " * <p class=clazz>baz<br>",
      " * baz",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void removeCloseTags() {
    String[] input = {
      "/**", //
      " * foo</p>",
      " *",
      " * <p>bar</p>",
      " */",
      "class Test {}",
    };
    String[] expected = {
      "/**", //
      " * foo",
      " *",
      " * <p>bar",
      " */",
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void javadocFullSentences() {
    String[] input = {
      "/** In our application, bats are often found hanging from the ceiling, especially on"
          + " Wednesdays.  Sometimes sick bats have issues where their claws do not close entirely."
          + "  This class provides a nice, grippable surface for them to cling to. */",
      "class Grippable {}",
    };
    String[] expected = {
      "/**",
      " * In our application, bats are often found hanging from the ceiling, especially on"
          + " Wednesdays.",
      " * Sometimes sick bats have issues where their claws do not close entirely. This class"
          + " provides a",
      " * nice, grippable surface for them to cling to.",
      " */",
      "class Grippable {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void javadocSentenceFragment() {
    String[] input = {
      "/** Provides a comfy, grippable surface for sick bats with claw-closing problems, which are"
          + " sometimes found hanging from the ceiling on Wednesdays. */",
      "class Grippable {}",
    };
    String[] expected = {
      "/**",
      " * Provides a comfy, grippable surface for sick bats with claw-closing problems, which are"
          + " sometimes",
      " * found hanging from the ceiling on Wednesdays.",
      " */",
      "class Grippable {}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void javadocCanEndAnywhere() {
    String[] input = {
      "/** foo <pre*/", //
      "class Test {}",
    };
    String[] expected = {
      "/** foo <pre */", //
      "class Test {}",
    };
    doFormatTest(input, expected);
  }

  private void doFormatTest(String[] input, String[] expected) {
    try {
      String actual = formatter.formatSource(Joiner.on('\n').join(input));
      assertThat(actual).isEqualTo(Joiner.on('\n').join(expected) + "\n");
    } catch (FormatterException e) {
      throw new AssertionError(e);
    }
  }

  @Test
  public void windowsLineSeparator() throws FormatterException {
    String[] input = {
      "/**", " * hello", " *", " * <p>world", " */", "class Test {}",
    };
    for (String separator : Arrays.asList("\r", "\r\n")) {
      String actual = formatter.formatSource(Joiner.on(separator).join(input));
      assertThat(actual).isEqualTo(Joiner.on(separator).join(input) + separator);
    }
  }

  @Test
  public void u2028LineSeparator() {
    String[] input = {
      "public class Foo {",
      "  /**\u2028",
      "   * Set and enable something.",
      "   */",
      "  public void setSomething() {}",
      "}",
    };
    String[] expected = {
      "public class Foo {",
      "  /**",
      "   * \u2028 Set and enable something.",
      "   */",
      "  public void setSomething() {}",
      "}",
    };
    doFormatTest(input, expected);
  }

  @Test
  public void missingSummaryFragment() {
    String[] input = {
      "public class Foo {",
      "  /**",
      "   * @return something.",
      "   */",
      "  public void setSomething() {}",
      "",
      "  /**",
      "   * @hide",
      "   */",
      "  public void setSomething() {}",
      "}",
    };
    String[] expected = {
      "public class Foo {",
      "  /**",
      "   * @return something.",
      "   */",
      "  public void setSomething() {}",
      "",
      "  /** @hide */",
      "  public void setSomething() {}",
      "}",
    };
    doFormatTest(input, expected);
  }
}
