net.sourceforge.pmd.lang.test.BaseTextComparisonTest.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pmd-lang-test Show documentation
Show all versions of pmd-lang-test Show documentation
Module containing utilities to test language implementations,
including parsers and ASTs. This module uses Kotlin.
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.test
import net.sourceforge.pmd.lang.document.FileId
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.test.assertEquals
/**
* Compare a dump of a file against a saved baseline.
* See subclasses CpdTextComparisonTest, BaseTreeDumpTest.
*/
abstract class BaseTextComparisonTest {
protected abstract val resourceLoader: Class<*>
/**
* Resource prefix to look for test files. This is
* resolved from the [resourceLoader] class. Separate
* directories with '/', not '.'.
*/
protected abstract val resourcePrefix: String
/** Extension that the unparsed source file is supposed to have. */
protected abstract val extensionIncludingDot: String
data class FileData(val fileName: FileId, val fileText:String)
/**
* Executes the test. The test files are looked up using the [resourceLoader].
* The reference test file must be named [fileBaseName] + [EXPECTED_EXTENSION].
* The source file to parse must be named [fileBaseName] + [extensionIncludingDot].
*
* @param transformTextContent Function that maps the contents of the source file to the
* "expected" format.
*/
internal fun doTest(fileBaseName: String,
expectedSuffix: String = "",
transformTextContent: (FileData) -> String) {
val expectedFile = findTestFile(resourceLoader, "${resourcePrefix}/$fileBaseName$expectedSuffix$EXPECTED_EXTENSION").toFile()
val actual = transformTextContent(sourceText(fileBaseName))
if (!expectedFile.exists()) {
expectedFile.writeText(actual.normalize())
throw AssertionError(
"""
Reference file doesn't exist, created it at $expectedFile
Don't forget to `git add` it!
""".trimIndent())
}
val expected = expectedFile.readText()
assertEquals(expected.normalize(), actual.normalize(), "File comparison failed, see the reference: $expectedFile")
}
protected fun sourceText(fileBaseName: String): FileData {
val sourceFile = findTestFile(resourceLoader, "${resourcePrefix}/$fileBaseName$extensionIncludingDot").toFile()
assert(sourceFile.isFile) {
"Source file $sourceFile is missing"
}
val sourceText = sourceFile.readText(Charsets.UTF_8).normalize()
return FileData(fileName = FileId.fromPath(sourceFile.toPath()), fileText = sourceText)
}
protected open fun String.normalize() = replace(
// \R on java 8+
regex = Regex("\\u000D\\u000A|[\\u000A\\u000B\\u000C\\u000D\\u0085\\u2028\\u2029]"),
replacement = "\n"
)
// Outputting a path makes for better error messages
private val srcTestResources = let {
// this is set from maven surefire
System.getProperty("mvn.project.src.test.resources")
?.let { Paths.get(it).toAbsolutePath() }
// that's for when the tests are run inside the IDE
?: Paths.get(javaClass.protectionDomain.codeSource.location.file)
// go up from target/test-classes into the project root
.resolve("../../src/test/resources").normalize()
}
private fun findTestFile(contextClass: Class<*>, resourcePath: String): Path {
val path = contextClass.`package`.name.replace('.', '/')
// normalize the path, because if eg we have src/test/resources/some/pack/../other,
// where the directory 'some/pack' does not exist, the file will not be found, even if
// some/other exists. Normalization turns the above path into src/test/resources/some/other
val norm = Paths.get("$path/$resourcePath").normalize()
return srcTestResources.resolve(norm)
}
companion object {
const val EXPECTED_EXTENSION = ".txt"
}
}