jdk-24/test/langtools/tools/javac/doctree/MarkdownTest.java
Jonathan Gibbons 0b8c9f6d23 8338525: Leading and trailing code blocks by indentation
Reviewed-by: hannesw, prappo
2024-09-24 20:09:40 +00:00

664 lines
15 KiB
Java

/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8298405
* @summary Markdown support in the standard doclet
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.tree
* jdk.compiler/com.sun.tools.javac.util
* @build DocCommentTester
* @run main DocCommentTester MarkdownTest.java
* @run main DocCommentTester -useStandardTransformer MarkdownTest.java
*/
/*
* Test for handling Markdown content.
*
* In the tests for code spans and code blocks, "@dummy" is used as a dummy inline
* or block tag to verify that it is skipped as part of the code span or code block.
* In other words, "@dummy" should appear as a literal part of the Markdown content.
* ("@Override" is also treated the same way, as a commonly found annotation.)
* Conversely, standard tags are used to verify that a fragment of text is not being
* skipped as a code span or code block. In other words, they should be recognized as tags
* and not skipped as part of any Markdown content.
*
* "@dummy" is also known to DocCommentTester and will not have any preceding whitespace
* removed during normalization.
*/
class MarkdownTest {
///abc < def & ghi {@code 123} jkl {@unknown} mno.
void descriptionMix() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 5
RawText[MARKDOWN, pos:0, abc_<_def_&_ghi_]
Literal[CODE, pos:16, 123]
RawText[MARKDOWN, pos:27, _jkl_]
UnknownInlineTag[UNKNOWN_INLINE_TAG, pos:32
tag:unknown
content: 1
Text[TEXT, pos:41]
]
RawText[MARKDOWN, pos:42, _mno.]
body: empty
block tags: empty
]
*/
///@since abc < def & ghi {@code 123} jkl {@unknown} mno.
void blockTagMix() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: empty
body: empty
block tags: 1
Since[SINCE, pos:0
body: 5
RawText[MARKDOWN, pos:7, abc_<_def_&_ghi_]
Literal[CODE, pos:23, 123]
RawText[MARKDOWN, pos:34, _jkl_]
UnknownInlineTag[UNKNOWN_INLINE_TAG, pos:39
tag:unknown
content: 1
Text[TEXT, pos:48]
]
RawText[MARKDOWN, pos:49, _mno.]
]
]
*/
///123 {@link Object abc < def & ghi {@code 123} jkl {@unknown} mno} 456.
void inlineTagMix() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 3
RawText[MARKDOWN, pos:0, 123_]
Link[LINK, pos:4
reference:
Reference[REFERENCE, pos:11, Object]
body: 5
RawText[MARKDOWN, pos:18, abc_<_def_&_ghi_]
Literal[CODE, pos:34, 123]
RawText[MARKDOWN, pos:45, _jkl_]
UnknownInlineTag[UNKNOWN_INLINE_TAG, pos:50
tag:unknown
content: 1
Text[TEXT, pos:59]
]
RawText[MARKDOWN, pos:60, _mno]
]
RawText[MARKDOWN, pos:65, _456.]
body: empty
block tags: empty
]
*/
///123 `abc` 456.
void simpleCodeSpan() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123_`abc`_456.]
body: empty
block tags: empty
]
*/
///123 `abc`
void simpleCodeSpanAtEndOfInput() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123_`abc`]
body: empty
block tags: empty
]
*/
///123 ```abc``` 456.
void mediumCodeSpan() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123_```abc```_456.]
body: empty
block tags: empty
]
*/
///123 ```abc`def``` 456.
void mediumCodeSpanWithBackTicks() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123_```abc`def```_456.]
body: empty
block tags: empty
]
*/
///123 ```abc{@dummy ...}def``` 456.
void mediumCodeSpanWithNotInlineTag() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123_```abc{@dummy_...}def```_456.]
body: empty
block tags: empty
]
*/
///123 ```abc
///@dummy def``` 456.
void mediumCodeSpanWithNotBlockTag() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123_```abc|@dummy_def```_456.]
body: empty
block tags: empty
]
*/
///123.
///```
///abc
///```
///456.
void simpleFencedCodeBlock_backtick() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 1
RawText[MARKDOWN, pos:5, ```|abc|```|456.]
block tags: empty
]
*/
///123.
///~~~
///abc
///{@dummy ...}
///~~~
///456.
void simpleFencedCodeBlock_tilde() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 1
RawText[MARKDOWN, pos:5, ~~~|abc|{@dummy_...}|~~~|456.]
block tags: empty
]
*/
///123.
///```
///abc
///```
void simpleFencedCodeBlock_atEndOfInput() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 1
RawText[MARKDOWN, pos:5, ```|abc|```]
block tags: empty
]
*/
///123.
///```
///abc {@dummy def} ghi
///```
///456.
void fencedCodeBlockWithInlineTag_backtick() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 1
RawText[MARKDOWN, pos:5, ```|abc_{@dummy_def}_ghi|```|456.]
block tags: empty
]
*/
///123.
///```
///abc ``` ghi
///{@dummy ...}
///```
///456.
void fencedCodeBlockWithBackTicks_backtick() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 1
RawText[MARKDOWN, pos:5, ```|abc_```_ghi|{@dummy_...}|```|456.]
block tags: empty
]
*/
///123.
///```abc`def``` 456.
void codeSpanNotCodeBlock() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 1
RawText[MARKDOWN, pos:5, ```abc`def```_456.]
block tags: empty
]
*/
///123.
///```
///{@code ...}
///~~~
///456.
void mismatchedFences() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 1
RawText[MARKDOWN, pos:5, ```|{@code_...}|~~~|456.]
block tags: empty
]
*/
///123.
///`````
///``` ghi
///{@dummy ...}
///`````
///456.
void fencedCodeBlockWithShortFence_backtick() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 1
RawText[MARKDOWN, pos:5, `````|```_ghi|{@dummy_...}|`````|456.]
block tags: empty
]
*/
///123.
///
/// abc {@dummy ...}
/// @dummy
/// def
///
///456 {@code ...}.
void indentedCodeBlock_afterBlank() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 3
RawText[MARKDOWN, pos:10, abc_{@dummy_...}|____@dummy|____def||456_]
Literal[CODE, pos:51, ...]
RawText[MARKDOWN, pos:62, .]
block tags: empty
]
*/
///123.
///### heading
/// abc {@dummy ...}
/// @dummy
/// def
///456 {@code ...}.
void indentedCodeBlock_afterATX() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 3
RawText[MARKDOWN, pos:5, ###_heading|____abc_{@dummy_...}|____@dummy|____def|456_]
Literal[CODE, pos:61, ...]
RawText[MARKDOWN, pos:72, .]
block tags: empty
]
*/
///123.
///Heading
///-------
/// abc {@dummy ...}
/// @dummy
/// def
///456 {@code ...}.
void indentedCodeBlock_afterSetext() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 3
RawText[MARKDOWN, pos:5, Heading|-------|____abc_{@dummy_...}|____@dummy|____def|456_]
Literal[CODE, pos:65, ...]
RawText[MARKDOWN, pos:76, .]
block tags: empty
]
*/
///123.
///- - - - -
/// abc {@dummy ...}
/// @dummy
/// def
///456 {@code ...}.
void indentedCodeBlock_afterThematicBreak() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 3
RawText[MARKDOWN, pos:5, -_-_-_-_-|____abc_{@dummy_...}|____@dummy|____def|456_]
Literal[CODE, pos:59, ...]
RawText[MARKDOWN, pos:70, .]
block tags: empty
]
*/
///123.
///```
///abc
///{@dummy}
///def
///```
/// abc {@dummy ...}
/// @dummy
/// def
///456 {@code ...}.
void indentedCodeBlock_afterFencedCodeBlock() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 3
RawText[MARKDOWN, pos:5, ```|abc|{@dummy}|def|```|____abc...mmy_...}|____@dummy|____def|456_]
Literal[CODE, pos:74, ...]
RawText[MARKDOWN, pos:85, .]
block tags: empty
]
*/
/// Indented Code Block
/// Lorum ipsum.
void indentedCodeBlock_leading() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: empty
body: 1
RawText[MARKDOWN, pos:0, ____Indented_Code_Block|Lorum_ipsum.]
block tags: empty
]
*/
/// Lorum ipsum.
///
/// Indented Code Block
void indentedCodeBlock_trailing() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, Lorum_ipsum.]
body: 1
RawText[MARKDOWN, pos:18, Indented_Code_Block]
block tags: empty
]
*/
///123.
///
///```
///public class HelloWorld {
/// @dummy
/// public static void main(String... args) {
/// System.out.println("Hello World");
/// }
///}
///```
///456 {@code ...}.
void fencedHelloWorld() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 3
RawText[MARKDOWN, pos:6, ```|public_class_HelloWorld_{|__..."Hello_World");|____}|}|```|456_]
Literal[CODE, pos:152, ...]
RawText[MARKDOWN, pos:163, .]
block tags: empty
]
*/
///123.
///
/// public class HelloWorld {
/// @dummy
/// public static void main(String... args) {
/// System.out.println("Hello World");
/// }
/// }
///
///456 {@code ...}.
void indentedHelloWorld() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, 123.]
body: 3
RawText[MARKDOWN, pos:10, public_class_HelloWorld_{|______...o_World");|________}|____}||456_]
Literal[CODE, pos:169, ...]
RawText[MARKDOWN, pos:180, .]
block tags: empty
]
*/
///{@summary abc ``code-span {@dummy ...}`` def {@code ...} }
///rest.
void codeSpanInInlineTag() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
Summary[SUMMARY, pos:0
summary: 3
RawText[MARKDOWN, pos:10, abc_``code-span_{@dummy_...}``_def_]
Literal[CODE, pos:45, ...]
RawText[MARKDOWN, pos:56, _]
]
body: 1
RawText[MARKDOWN, pos:58, |rest.]
block tags: empty
]
*/
///{@summary abc
///```code-block
/// {@dummy ...}
///```
///def {@code ...} }
///rest.
void codeBlockInInlineTag() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
Summary[SUMMARY, pos:0
summary: 3
RawText[MARKDOWN, pos:10, abc|```code-block|__{@dummy_...}|```|def_]
Literal[CODE, pos:51, ...]
RawText[MARKDOWN, pos:62, _]
]
body: 1
RawText[MARKDOWN, pos:64, |rest.]
block tags: empty
]
*/
///abc `
///def
void unmatchedBackTick() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, abc_`|def]
body: empty
block tags: empty
]
*/
///{@summary abc `
///def}
///rest
void unmatchedBackTickInInline() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
Summary[SUMMARY, pos:0
summary: 1
RawText[MARKDOWN, pos:10, abc_`|def]
]
body: 1
RawText[MARKDOWN, pos:20, |rest]
block tags: empty
]
*/
// While this is an important test case, it is also a negative one
// (that is, the AST contains an Erroneous node).
// Note how the backticks "match" across the end of the inline tag.
// That's unfortunate, but cannot reasonably be detected without
// examining the contents of a code span.
// Not surprisingly, some of the checks fail for this (bad) test case.
// * PrettyChecker fails because it does not handle an unterminated inline tag.
// * StartEndPosChecker fails because it does not handle an unterminated inline tag.
//
// Disabled until we can either enhance the checkers or select which
// checkers to use.
// ///{@summary abc `
// ///def}
// ///rest `more`
// ///
// void unmatchedBackTickInInline2() { }
///*
//DocComment[DOC_COMMENT, pos:0
// firstSentence: 1
// Summary[SUMMARY, pos:0
// summary: 1
// Erroneous[ERRONEOUS, pos:10, prefPos:31
// code: compiler.err.dc.unterminated.inline.tag
// body: abc_`|def}|rest_`more`
// ]
// ]
// body: empty
// block tags: empty
//]
//*/
///Indented by 0.
///
/// * list
///
/// code block
///
///done.
void indent0() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, Indented_by_0.]
body: 1
RawText[MARKDOWN, pos:19, *_list||____code_block||done.]
block tags: empty
]
*/
/// Indented by 1.
///
/// * list
///
/// code block
///
/// done.
void indent1() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, Indented_by_1.]
body: 1
RawText[MARKDOWN, pos:19, *_list||____code_block||done.]
block tags: empty
]
*/
/// Indented by 8.
///
/// * list
///
/// code block
///
/// done.
void indent8() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: 1
RawText[MARKDOWN, pos:0, Indented_by_8.]
body: 1
RawText[MARKDOWN, pos:19, *_list||____code_block||done.]
block tags: empty
]
*/
// The following test case is derived from the test case in JDK-8338525.
/// @Override
/// void m() { }
///
/// Plain text
///
/// @Override
/// void m() { }
void leadingTrailingCodeBlocksWithAnnos() { }
/*
DocComment[DOC_COMMENT, pos:0
firstSentence: empty
body: 1
RawText[MARKDOWN, pos:0, ____@Override|____void_m()_{_}||...||____@Override|____void_m()_{_}]
block tags: empty
]
*/
}