Documentation

This commit is contained in:
Clément Fournier
2018-09-04 12:30:30 +02:00
parent 86a1a13dc6
commit 4a3f85d40a
3 changed files with 51 additions and 2 deletions
@@ -14,7 +14,7 @@ class ASTCatchStatementTest : FunSpec({
parserTest("Test crash on multicatch", javaVersions = Earliest..J1_6) {
expectParseException("Cannot catch multiple exceptions when running in JDK inferior to 1.7 mode!") {
expectParseException("Cannot catch multiple exceptions when running in JDK inferior to 1.7 mode") {
parseAstStatement("try { } catch (IOException | AssertionError e) { }")
}
@@ -4,6 +4,8 @@ import net.sourceforge.pmd.lang.ast.Node
/** Extension methods to make the Node API more Kotlin-like */
// kotlin converts getters of java types into property accessors
// but it doesn't recognise jjtGet* methods as getters
val Node.numChildren: Int
get() = this.jjtGetNumChildren()
@@ -81,16 +81,59 @@ fun AbstractFunSpec.parserTest(name: String,
}
/**
* Extensible environment to describe parse/match testing workflows in a concise way.
* Can be used inside of a [io.kotlintest.specs.FunSpec] with [parserTest].
*
* Parsing contexts allow to parse a string containing only the node you're interested
* in instead of writing up a full class that the parser can handle. See [parseAstExpression],
* [parseAstStatement].
*
* The methods [parseExpression] and [parseStatement] add some sugar to those by skipping
* some nodes we're not interested in to find the node of interest using their reified type
* parameter.
*
* These are implicitly used by [matchExpr] and [matchStmt], which specify a matcher directly
* on the strings, using their type parameter and the info in this test context to parse, find
* the node, and execute the matcher in a single call. These may be used by [io.kotlintest.should],
* e.g.
*
* parserTest("Test ShiftExpression operator") {
* "1 >> 2" should matchExpr<ASTShiftExpression>(ignoreChildren = true) {
* it.operator shouldBe ">>"
* }
* }
*
*
* Import statements in the parsing contexts can be configured by adding types to [importedTypes],
* or strings to [otherImports].
*
* Technically the utilities provided by this class may be used outside of [io.kotlintest.specs.FunSpec]s,
* e.g. in regular JUnit tests, but I think we should strive to uniformize our testing style,
* especially since KotlinTest defines so many.
*
* TODO allow to reference an existing type as the parsing context, for full type resolution
*
* @property javaVersion The java version that will be used for parsing.
* @property importedTypes Types to import at the beginning of parsing contexts
* @property otherImports Other imports, without the `import` and semicolon
*/
data class ParsingTestCtx(val javaVersion: JavaVersion = JavaVersion.Latest,
val importedTypes: MutableList<Class<*>> = mutableListOf(),
val otherImports: MutableList<String> = mutableListOf()) {
/** Imports to add to the top of the parsing contexts. */
private val imports: List<String>
get() {
val types = importedTypes.mapNotNull { it.canonicalName }.map { "import $it;" }
return types + otherImports.map { "import $it;" }
}
/**
* Returns a String matcher that parses the node using [parseExpression] with
* type param [N], then matches it against the [nodeSpec] using [matchNode].
*
*/
inline fun <reified N : Node> matchExpr(ignoreChildren: Boolean = false,
noinline nodeSpec: NWrapper<N>.() -> Unit): Matcher<String> =
object : Matcher<String> {
@@ -99,6 +142,10 @@ data class ParsingTestCtx(val javaVersion: JavaVersion = JavaVersion.Latest,
}
/**
* Returns a String matcher that parses the node using [parseStatement] with
* type param [N], then matches it against the [nodeSpec] using [matchNode].
*/
inline fun <reified N : Node> matchStmt(ignoreChildren: Boolean = false,
noinline nodeSpec: NWrapper<N>.() -> Unit) =
object : Matcher<String> {
@@ -143,7 +190,7 @@ data class ParsingTestCtx(val javaVersion: JavaVersion = JavaVersion.Latest,
Object o = $expr;
}
}
""".trimIndent()
""".trimIndent()
val acu = ParserTstUtil.parseAndTypeResolveJava(javaVersion.pmdName, source)